nc://deadbolt

v0.1.0Pinned
ThomSharktools/nodecode-deadbolt: Review and approve exact new text files before the agent creates them, through a local DeadBolt sidecar. - a rewrite of seanebones-lang/deadbolt-hermes-plugin (Apache-2.0), credited to seanebones-lang6a6f74e· 9 Nov1 commit
test1 filecell.lisp11.3 KBLICENSE11.1 KBreview.lisp12.1 KB

nodecode-deadbolt

DeadBolt: review and approve an exact new text file before the agent writes it. A Nodecode rewrite of seanebones-lang/deadbolt-hermes-plugin by seanebones-lang.

An agent that writes a report, a generated config or any other text artifact usually writes it and tells you afterwards. With this cell the agent proposes the exact destination and the exact UTF-8 text first, a person reads it in a terminal they own, and only then is the file created. Two tools carry it:

  • deadbolt_prepare_write saves a private review request — workspace, path, the exact content, a nonce and a deadline — and creates nothing.
  • deadbolt_commit_write asks a separately running DeadBolt 2.0.0 sidecar for exact admission of that request, and only on an allow creates the one new file. A denial writes nothing. The grant binds the run, the tool, the workspace, the path, the content, the nonce and the deadline, and it is spent once.

The cell is the same two tools, the same envelope, the same loopback call and the same files as the plugin, reimplemented in Common Lisp against Nodecode's cell contract. What a person does outside the agent is unchanged: the request file is plain JSON, and deadbolt action inspect --file … reads it.

Get it

Tell the agent "add the deadbolt cell", or run nodecode add nc://deadbolt.

Set it up

This cell is a gate in front of a service, so the service comes first. Install the DeadBolt engine (Apache-2.0, a separate project) and provision one finite run with a policy for this tool id and a scoped admission credential:

deadbolt ensure --agent report-001 --lease-ttl-secs 3600
deadbolt policy --agent report-001 --tools hermes_artifact_write_v1
deadbolt action require --agent report-001 --tool hermes_artifact_write_v1
deadbolt credential issue --agent report-001 --id report-admission-001 \
  --ttl-secs 3600 --out /absolute/private/path/new-admission-credential
deadbolt serve --bind 127.0.0.1:9782 --lease-ttl-secs 3600

The tool id stays hermes_artifact_write_v1 because that is the name the engine's policy is written against; a policy already made for the plugin admits this cell's actions unchanged. The operator token stays in the sidecar: the cell never sees it, and never wants it.

Then give the cell its section, in ~/.nodecode/config.jsonc:

{
  "deadbolt": {
    "workspace": "/absolute/path/to/reviewed-output",
    "run_id": "report-001",
    "sidecar_port": 9782,
    "admission_token_env": "DEADBOLT_ADMISSION"
  }
}

with the scoped credential in the environment Nodecode runs in, or pasted into admission_token instead (exactly one of the two). workspace is an existing absolute directory; review_dir is optional and defaults to deadbolt/requests under the nodecode home. /deadbolt says where the three stand and how many requests are waiting, and (restart-cells "nodecode-deadbolt") tries again after a fix.

Use it

The model calls the two tools; a person works the requests. Typed alone, /deadbolt reports the workspace, the run, the port, whether a credential is set and what waits; /deadbolt pending lists the requests still in the review directory. From eval the same verbs are ordinary functions:

(deadbolt:prepare "report.md" "A fictional reviewed report.")
;; => ("prepared": true, "request_id": "9f2c…", "review_file": "…/9f2c….json",
;;     "expires_at": 1794000000, "output_created": false, "next_action": …)
(deadbolt:commit "9f2c…")
;; => ("admitted": true, "completed": true, "result": ("path": "report.md", "bytes": 28))
(deadbolt:pending)   ; what is still waiting, newest first

In the operator's terminal, between the two:

deadbolt action inspect --file /the/exact/returned/review-file.json
deadbolt action approve --file /the/exact/returned/review-file.json \
  --fingerprint sha256:THE_DIGEST_YOU_ACTUALLY_REVIEWED

What it does and does not protect

Only this cell's own commit is gated. Nodecode's file tools, the shell, the browser, MCP servers and every other cell go around it, so keep Nodecode's own approvals on; this is a reviewed-artifact route, not whole-agent containment. It creates new files only — never an overwrite, a patch or a delete — the parent directory must exist, one request envelope is at most 32768 bytes by default, and the walk refuses .., an absolute path, a parent that leaves the workspace once its symbolic links are followed, and an existing file.

A prepared request holds the raw proposed text: it is written 0600 in a 0700 directory, it is not encrypted, and it stays after the commit for the operator to read or remove. The only outbound connection is HTTP to the literal 127.0.0.1 at the configured port, endpoint /admit-action, carrying the envelope and the one scoped credential; there is no redirect, no remote service and no telemetry. Admission is not completion: a write that fails after admission answers admitted: true, completed: false, outcome: "unknown", and the destination is then the operator's to inspect before anything is retried.

Test

From this repository's root:

.github/test-cell.sh tools/nodecode-deadbolt

Every exchange with the sidecar is stubbed, so the slice runs offline.

Apache-2.0. See NOTICE for what was rewritten from the plugin.

Add nc://deadbolt

  1. 1

    Install Nodecode

    Once per machine.

    $ curl -fsSL https://nodecode.ai/install.sh | sh
  2. 2

    Add the cell

    Pinned at 6a6f74e.

    $ nodecode add nc://deadbolt

    Or tell the agent add the deadbolt cell.