Devplane

The decision log

What Devplane did or refused, on whose authority, and with which rule or check — kept after everything else is pruned.

The decision log holds what Devplane did or refused, and on whose authority. Use it to answer why did that command run unasked? or why is there a pull request on this branch?

devplane audit                  # the latest 50 decisions
devplane audit <run-or-change>  # one run or change
devplane audit --without-me     # only what was decided instead of you
devplane audit --otel           # OpenTelemetry GenAI log records on stdout
2026-09-13T18:04:11 person   github:pr.create https://github.com/acme/app/pull/142
                     ↳ offered as a draft
2026-09-13T18:04:09 person   git:push         change/fix-the-flaky-login-test-a1b2c3
                     ↳ offered the change
2026-09-13T18:04:02 devplane gate:run         pnpm typecheck && pnpm test -- --run
                     ↳ check passed
2026-09-13T17:58:40 rule     agent:tool.use   Bash: rm -rf /tmp/build
                     ↳ refused by Bash(rm *)
2026-09-13T17:41:09 timer    agent:tool.use   Bash: pnpm publish
                     ↳ a clock refused it after 4h — set in devplane.toml
2026-09-13T17:22:55 nobody   agent:question   req-7c03
                     ↳ the run ended under the question

The workbench’s Ledger and each change’s Ledger tab show the same rows.

The ledger: what Devplane recorded as decided, when, on whose authority, and the rule behind each verdict

Reading a row

A row has an authority, an action, a subject, an outcome and a reason.

AuthorityMeans
personsomebody was asked and answered. The reason names the path: the window, the notification, or the cli for anything else holding the control token, a browser tab included (where an answer came from)
rulea deny or ask rule matched, or your own grant allowed the call. The reason names the rule or the grant. A line the gate could not read is rule with outcome unresolved
timernobody answered before your project’s [questions] deadline; the reason names the duration and file
nobodyasked, never answered, and the moment passed: the run ended under the question, or a held permission lapsed. Quitting the host cleanly leaves the question open
devplaneDevplane carrying out what your project wrote down: a gate run, a budget stop

A row without an established authority is not written; there is no unknown. A push and a pull request are person, because you offered the change.

ActionRecorded for
agent:tool.use, agent:questiona tool call or a question an agent put
gate:runa gate run on a change
git:push, github:pr.createan offered change
change:…what you did to a change: adopt, retry, resume, stop, done, archive, draft, draft.accept, draft.reject, drift.accepted, drift.told, agent.switch, agent.sign_in
run:resume, run:stopthe same for a run
spec:clarifyan open question answered in a specification
config:open_questions[spec] open_questions written into devplane.toml at your word
policy:grant, policy:revoke, policy:explaina grant written or removed; an explain asked of the host, such as over MCP
  • --without-me drops person and devplane rows and adds the Not attributed list below.
  • --otel writes the authority on each gen_ai.tool.call.decision record. Nothing is sent.
  • devplane status --modes shows the sessions that never prompt.

A session you started yourself

With Claude Code’s telemetry connected (devplane agent connect claude), every permission decision Claude Code reports for your own session is recorded, with its own word beside the authority (↳ Claude Code: user_reject). An authority is written only where that word has one reading:

Claude Code reportsRecorded as
user_permanent, user_temporary, user_abort, user_reject, in the terminal CLIperson
the same in an Agent SDK, -p, IDE or desktop sessionnot attributed: there a saved rule’s match is reported the same way
config, with a rule in your Claude Code settings that matches the callrule, naming the rule and its file
config otherwisenot attributed
hookDevplane’s own row for that call; another program’s hook is not attributed
no source, or a value Claude Code does not documentnot attributed, with the value as received

config reads rule only when the permission mode at that moment is known, is not auto mode and does not allow the call by itself, and a readable settings rule matches with the same effect.

devplane audit --without-me lists every other reported call under Not attributed:

Not attributed (3)
2026-09-30T10:01:00 Bash     accept  could not be attributed — auto mode was on
                     ↳ Claude Code: config
ReasonWhen
auto mode was ona rule, an earlier grant or Claude Code’s classifier may have decided
the permission mode was not knownnothing Claude Code sent names the mode at that moment
the mode allowed itthe mode allows the call by itself (accept edits, bypass permissions)
Claude Code’s settings decided and do not say howno readable rule matches the call
Claude Code reports a saved rule’s match as the person’s in this kind of sessiona user_* report outside the terminal CLI
a hook decided — no hook decision Devplane recorded names this callanother program’s hook, or Devplane’s PermissionRequest hook, which carries no call id
the vendor sent no source / sent “…”the source was missing or undocumented
  • The mode in force is read from Claude Code’s own timestamps and order, not from arrival time.
  • Telemetry never answers a permission; only the hook’s or the protocol’s answer clears one.
  • devplane doctor names any undocumented source value Claude Code sent, with when it was first seen.
  • The Not attributed list lives with the session’s events and is pruned with them.

No decision is recorded as a model’s. Codex’s auto-review is a reviewer model deciding, and no channel Devplane reads carries those decisions, so none is recorded. A driven Codex session in Auto review says decides without you: a reviewer model decides.

What the log keeps

  • Decisions and asks are never pruned. Events, telemetry and transcripts are pruned after 30 days, finished runs after 7.
  • The hook writes decisions directly, with no host. When the store will not open they go to ~/.devplane/pending-decisions.jsonl; devplane doctor counts them and the next host files them, marked late.
  • A store schema change starts a new store with an empty Ledger; the old file stays readable (Troubleshooting).

What is not in the log

  • An undecided call: your agent’s own dialog answered it.
  • Calls under an agent’s “allow always”: the row that chose it says allow_always; later matching calls do not appear.
  • A Claude Code mod that refuses a call, and an approval given in the chat rather than at the prompt: Claude Code reports no source for either.
  • A watched call with telemetry off: nothing is reported, and nothing is inferred.

Limits

  • The log is an append-only local SQLite file. It is not tamper-evident (Security).
  • Devplane’s own actions are safe to repeat: a gate is a read, a branch pushed twice is one branch, and an existing pull request is looked up first.

Something wrong or out of date? Edit this page.