Repository navigation
v0.13.0
Added
- The sandbox boundary for coding and rework agents ships, off by default (issue #502).
docs/SANDBOX_BOUNDARY.md§6.3's frozen config —sandbox.enabled, a narrow
filesystem.allowWrite,network.strictAllowlistwith a measuredallowedDomainslist,
anddenyon the GitHub token file — is now written to a chela-owned
<claude config dir>/chela-sandbox.settings.jsonand passed as--settings <path>to a
dispatched coding or rework agent whose workflow opts in withagent.sandbox: truein its
WORKFLOW.md. The judge is excluded unconditionally (role="judge"short-circuits before
the opt-in check), since it runs a fixed command in a throwaway tree and never pushes,
while a coding agent takes an arbitrary task description and pushes to a public repo.
CMX-366 (the completion hop) and CMX-368 (the push/PR-open) already moved the two
privileged effects that would have made this cosmetic onto the daemon; this lands the
config itself. A workflow that has not opted in launches byte-identically to today.
(CMX-369, #518)
Changed
-
The completion hop is now the daemon's write, not the dispatched agent's (issue #502).
chela task-finishedused to runUPDATEs against~/.chela/scheduler.dband kill the
agent's tmux window inside the agent's own process — the single thing blocking OS-level
sandboxing of dispatched agents, since an agent that can write the runs DB can rewrite every
other run's row, and one that can reach the tmux control socket cansend-keysinto any
window, including the operator's, with nofromattribution.chela task-finishednow
writes a request marker into the run's own worktree (a path the agent can already write,
sandboxed or not);tick(), unsandboxed and already polling every run, picks the marker up
and performs the transition toawaiting_reviewand the window kill on the daemon's side. A
request the daemon cannot apply for an unexplained reason (not: someone else already settled
the row) now escalates the run toneeds_humanand keeps the marker as evidence, instead of
logging a warning nobody reads and leaving the rowrunningforever.
(CMX-366) -
The push and the PR open are now the daemon's, not the dispatched agent's (issue
#502). Done Criteria step 5 used to rungit pushthengh pr createinside the
agent's own process — the second blocker (after CMX-366's completion hop) standing
between OS-level sandboxing and being cosmetic. Measured with a matched unsandboxed
control (docs/SANDBOX_BOUNDARY.md§5 B2): masking the GitHub token keepsghworking
(it sendsAuthorization: token <token>verbatim, so the sandbox's substring
substitution catches it) but notgit push(it sendsAuthorization: Basic base64(user:token), so the token is never present verbatim and nothing is substituted —
GitHub rejects the push).chela request-push <task_id> [--pr-title T --pr-body-file P]
now writes a request marker into the run's own worktree instead (a path the agent can
already write, sandboxed or not);tick(), unsandboxed and already polling every run,
picks the marker up, pushes the branch, and — only when the run has nopr_urlyet —
opens the PR, so the token never has to enter the agent's process at all. A request that
keeps failing gets 5 ticks to succeed before it escalates toneeds_human, preserving the
marker as evidence, instead of retrying forever and pinning the run's concurrency slot.
(CMX-368)
Fixed
-
npm-shared-install.shnow checks whether the declared npm packages actually resolve,
not whether the sharednode_modulesis empty. The previous freshness check
(-z "$(ls -A ...)") still read a partially-unpacked shared install — e.g. one left by an
npm ciinterrupted mid-unpack — as "already installed" if it had any content at all, so a
worktree could symlink into a sharednode_modulesstill missing jsdom. The check now
reuseschela.judge's owndeclared_npm_packages/_unresolvablehelpers. (CMX-367, #510) -
ensure_schemanow names the missing column and the underlying sqlite reason when a
migration genuinely fails (a read-only connection whose schema is missing a column,
e.g. a sandboxed agent's denied~/.chelawrite). Anyone running chela against a database
they cannot write now gets a loud, specificSchemaMigrationErrorinstead of an inscrutable
no such columnsurfacing later, elsewhere. (CMX-370, #519) -
context.ensure_schemanow names the missing column and the underlying sqlite reason when
a migration genuinely fails (a read-only connection whosecontext_snapshotsschema is
missing a column, e.g. a sandboxed agent's denied~/.chelawrite). Anyone running chela
against a database it cannot write now gets a loud, specificSchemaMigrationErrorinstead
of an inscrutableno such columnsurfacing later, elsewhere. (CMX-371, #520)