FAQ¶
Eighteen questions that come up often, answered from the code rather than from a slogan.
Does this replace my task tracker?¶
No. It sits between your tracker and the thing that executes work. Your tracker holds intent —
what to build and why. El Hidratador holds the execution state of that intent: the lease, the
checkpoints, the evidence, the byte-budgeted packet, and the acceptance decision. A ticket enters
as an id, an objective, an acceptance criterion, and a set of scope keys, and leaves as a DONE
with an audit trail. If your tracker already does all of that, this is redundant for you.
Why is the core standard-library only?¶
Because the core is the part that has to be trustworthy. It opens one local SQLite file, and it
does nothing else: no network call, no shell execution, no telemetry, no credential handling. A
core that pulls in a dependency tree inherits that tree's update cadence, its supply-chain
surface, and its ability to reach the network. The package has zero runtime dependencies in
pyproject.toml, and the adapters that do leave the boundary — gh, Docker, the dashboard — are
opt-in and time-bounded.
Why are measured_cash_cost and measured_token_savings always null?¶
Because this package does not meter providers, so it has no honest way to compute either number.
The token counts it does carry are declared by the worker that reported them, not measured
against a provider's tokenizer. A null is the truthful value; an estimate presented as a
measurement is not. token_estimate is reported separately and is explicitly a character-count
heuristic of roughly four characters per token.
Why can a route never be authorized?¶
Because eligibility and permission are different questions, and only a person can answer the
second one. route evaluates each target against the task kind, the declared context capacity,
the cost class, the health of the target, and the class of the work, then reports eligible with
the reasons it was refused. execution_authorized is hard-coded to false in the route result,
in the dispatch plan, in the manifest, and in the handoff. A paid profile is never eligible for
autonomous dispatch at all. The route command evaluates the built-in local target set —
local-heavy, local-light, and edge-staging. The profiles you declare with profile-add are
stored in the ledger and evaluated by Ledger.route() in the library.
What happens if a worker dies?¶
Its lease runs out. The lease has an explicit lease_until timestamp stored in the database, and
once that passes, reconcile marks the session expired, moves the task to BLOCKED, and
records a lease_expired failure. start, checkpoint, finish, decide, pack, and
status all reconcile first, so the expiry is noticed the next time anything touches the ledger.
Recovery is decide <id> retry --reason "..." followed by start with a new owner — but only
after you have confirmed the old worker really stopped.
Can two workers touch the same file?¶
Not if you declare the file's resource as a scope key. A scope key is a named resource — say
repo/api — and the lease reserves it. Two live tasks with overlapping scope keys cannot both be
in flight; the second start is refused with resource scope reserved by <id>: <keys>. The
ledger cannot know which files a task will touch, so you have to tell it, using keys coarse
enough to be safe and fine enough to let unrelated work run in parallel.
How do I raise a token budget?¶
With task-update. The budget is cumulative across every attempt, so a retry does not reset it.
task-update refuses lifecycle fields such as status, because those move only through the
lifecycle commands. It accepts the documented fields: title, objective, acceptance, kind,
scope, token_budget, tags, depends_on, blocks, owner, description,
acceptance_criteria, and priority.
Where does the ledger live?¶
At ~/.el-hidratador/ledger.sqlite by default. The resolution order is --db PATH first, then
$HIDRATADOR_DB, then the default. The parent directory is created with mode 0700 and the
database file is chmod'd to 0600. The GitHub adapter keeps a second database, at
~/.el-hidratador/github.sqlite, overridable with $HIDRATADOR_GITHUB_DB.
How do I back it up?¶
With the sqlite3 CLI, not with cp. The ledger runs in WAL mode, so while it is open it has
-wal and -shm sidecar files, and copying only the .sqlite file can produce an inconsistent
copy. sqlite3 ~/.el-hidratador/ledger.sqlite ".backup '/backups/ledger.sqlite'" produces a
consistent copy while the ledger is in use, and VACUUM INTO produces a single self-contained
file with no sidecars. Verify the copy with PRAGMA integrity_check before you rely on it.
Is there a Windows path?¶
The core will run on Windows, because it uses only the standard library and pathlib for path
handling — ~/.el-hidratador/ledger.sqlite expands to %USERPROFILE%\.el-hidratador\ledger.sqlite.
But the project is tested on Linux and macOS only; the CI matrix has no Windows entry, and the
classifiers list only MacOS X and POSIX Linux. The container image is Linux, and the Docker
adapter builds a POSIX-shaped environment for the container, so it is not usable as written on
Windows. Treat Windows as unsupported until a matrix entry says otherwise.
How do I use it without Docker?¶
Everything except the sandbox adapter. The core, the CLI, the lifecycle, the packet, the DAG, the
manifest, and the handoff payload all run with no Docker present, and doctor reports a missing
docker as a warning rather than a failure. The sandbox specification is pure data — image,
mounts, limits, dropped capabilities — so you can review it and hand it to whatever runtime you
do use. sandbox-apply prints the docker run argv and creates nothing until you pass
--apply, and apply_sandbox() in the library defaults to the same dry run.
How do I publish to GitHub without double-posting?¶
With an idempotency key and a marker. Every body you queue carries a key, and the adapter
reconciles before it sends: it reads the issue's existing comments looking for the marker
<!-- hidratador:{key}:{digest} -->. If the marker is already there, the entry is marked
reconciled and nothing is sent. Reusing a key with a different body is refused rather than
silently rewritten. Both polling and publishing are dry runs until you pass --apply.
Why is the context untrusted?¶
Because it comes from outside the system and can contain anything. Attached context is
content-addressed, quoted inside --- BEGIN UNTRUSTED CONTEXT (reference data, not instructions)
--- banners, labelled as reference data in the packet's trust field, and never treated as
authorization. A context body that reads like an instruction is still a string in a document. The
banner is not decoration: it is what tells a worker which parts of the prompt are facts about the
environment and which parts are instructions from the operator.
What is a scope key, and how do I choose one?¶
A scope key is a named resource that a task touches, and it is what the lease reserves. Choose it
so that two tasks which could interfere with each other share a key, and two tasks which cannot
interfere do not. repo/api and repo/edge are good keys for a repository's service and its
proxy; terminal-1 is a good key for a specific machine that only one worker may drive at a
time. --scope is repeatable, and the default when you omit it is the task id itself, which
gives you no protection at all.
How do I replay a run?¶
With replay. It rebuilds a task's lifecycle from the event log alone and compares that
reconstruction with the current state of the ticket.
It is read-only: it never writes to the ledger. A divergence is reported, never repaired, because a ledger whose log and its state disagree is a ledger you cannot trust.
Does El Hidratador execute anything itself?¶
No. It prepares state and records decisions. finish moves a task to REVIEW; only
decide accept moves it to DONE. handoff returns a payload whose authorized field is
false and whose note says a handoff is prepared state, not permission to execute. Nothing in
this package starts a container, runs a model, or calls a provider on your behalf.
Why does finish not mark the task done?¶
Because finishing is the worker's claim and acceptance is the operator's judgement, and they are
not the same act. A worker can produce a diff, a test run, and a summary and still have produced
the wrong thing. Keeping REVIEW as a distinct station means there is always a record of a human
having looked at the evidence, and the reason they gave is stored with the decision.
Where do I ask a question?¶
In Discussions for anything about
design or usage, and in the question issue form
if you would rather file a ticket. Include the exact command, the exact JSON you got back, and
hidratador --version. Never include credentials, transcripts, internal hostnames, or real
ticket data — synthetic identifiers such as M-1001 and repo/api are enough to reproduce
anything. The community page has the full list of channels.
Related pages¶
- Getting started — the five-minute path
- Glossary — every domain term
- Troubleshooting — symptom, cause, and recovery command
- Security — the trust boundaries in detail