Skip to content

Releases: marcelocantos/doit

v0.9.0

Choose a tag to compare

@marcelocantos marcelocantos released this 25 Apr 15:01
7c9efdb

doit v0.9.0

Postmortem-tooling release. The audit log now captures every signal an
operator (or agent) needs to reconstruct why doit made a decision — not
just what decision it made — and the new doit_audit_query MCP tool
makes those signals reachable by filter rather than tail-by-count.

Added

  • 🎯T37 — L3 chain-of-evidence in the audit log. Every L3 invocation now
    records a structured l3_fast block (and l3_deep when the cascade
    fires both tiers) containing the model name, rendered prompt, model
    response, latency, decision, and reason. Configurable size cap via
    audit.l3_max_chars (default 16384 per block) with explicit truncation
    marker. The single biggest postmortem black hole — "why did L3 allow
    that?" — is now answerable.

  • 🎯T36 — Elicitation outcomes and L2 promotions in the audit chain.
    Phase 1 elicitation (Allow once / Allow always / Deny once / Deny always)
    and Phase 2 promotion (rule proposed, accepted, or declined) each
    produce their own audit-chain entry, linked to the originating command
    via the new parent_seq field. New fields: parent_seq,
    elicitation_prompt, elicitation_choice, elicitation_latency_ms,
    proposed_rule_source, proposed_rule_generality, proposed_rule_id.
    Reflexive-vs-deliberated approvals are now visible as latency
    outliers; rule provenance is no longer lost.

  • 🎯T39 — stdout/stderr excerpts for failure-mode commands. When a
    command's audit entry would record exit_code != 0, policy_result == deny, or timed_out == true, doit now captures up to 4096 bytes of
    stdout and stderr into new stdout_excerpt / stderr_excerpt fields.
    Configurable via audit.capture_output (always / on_failure /
    never, default on_failure) and audit.output_excerpt_bytes. UTF-8-
    safe truncation with […truncated, total N bytes] marker. New
    RedactOutput() bool method on cap.Capability is forward-compatible
    scaffolding for sensitive-command exclusion (no capability sets it
    today).

  • 🎯T38 — doit_audit_query MCP tool. Filter-based postmortem lookup
    replaces tail-by-count as the primary primitive. Filters: policy_result,
    policy_level, rule_id, cwd_substring, project_root, since
    (RFC3339 or relative duration like 1h), until, exit_code (number
    or "nonzero"), cap, command_substring, parent_seq, limit
    (default 20, max 200). latest=true returns the single most-recent
    match — the primary postmortem path. include (l3 / excerpts /
    elicitation) opts into the heavy fields; default response strips
    them to keep result size sane.

Documentation

  • agents-guide.md and README.md describe the new doit_audit_query
    workflow with concrete usage examples ("the last thing doit refused",
    "all L3 escalations in the last hour with prompt + response", "the
    elicitation chain that created rule X").
  • STABILITY.md snapshot bumped to v0.9.0; the postmortem-tooling batch
    is recorded as a closed pre-1.0 gap. Field-level annotations on the
    new audit fields and config knobs remain Needs review until the
    schema settles through real-world use.

v0.8.0

Choose a tag to compare

@marcelocantos marcelocantos released this 25 Apr 12:00
fa0308b

doit v0.8.0

Threat-model-driven safety improvements — three pre-1.0 follow-ons to the
v0.7.0 threat model land in this release, plus per-project anomaly calibration
and a recoverability-aware rm tier.

Added

  • 🎯T33 — doit_check_config reports the full safety contract. The tool
    now surfaces all seven load-bearing settings the threat model names, with
    stable §N markers tying each result back to
    docs/threat-model.md. [FAIL] for missing Bash
    deny-list / doit registration; [INFO] / [WARN] for sibling MCP servers,
    dangerous-tier state, policy-store permissions, L3 model overrides, and
    per-project config presence. Settings weakened from defaults are now
    visually distinct from informational items.

  • 🎯T34 — Startup warning for sibling MCP servers with execution-adjacent
    primitives.
    doit emits a warning at MCP-server startup when other
    registered servers expose shell execution, file-write+chmod, language
    runtimes, or HTTP-to-localhost patterns that bypass doit's policy engine.
    Suppressible per-server via the new
    policy.acknowledged_sibling_servers: [...] config field. Backed by a
    classification heuristic in the new internal/mcpinventory package.

  • 🎯T35 — L3 prompt-injection surface enumerated, hardened, and tested.
    New docs/l3-injection.md document enumerates
    every untrusted input flowing into the L3 prompt with per-input trust
    level, position, mitigation, and gap classification. The L3 prompt
    template now wraps every agent-supplied field (command, cwd,
    justification, safety argument, session scope, session description) in
    XML data tags with full XML character escaping, and instructs the model
    to treat tag contents as data only. A 10-payload prompt-injection
    regression corpus lives in internal/llm/testdata/injection_corpus.yaml
    and is exercised by the renderer test on every CI run.

Changed

  • 🎯T29 — Learned duration statistics keyed per-project. Duration
    aggregation now keys on (cap, subcmd, project_id) rather than the
    global (cap, subcmd), so a small repo's make test percentiles no
    longer pool with a monorepo's. project_id derives from the project
    root path; commands without a project context fall back to a shared
    bucket. Eliminates a class of false-positive anomaly flags in both
    directions.

  • 🎯T30 — rm tier reflects reversibility via git-tracked status. A
    non-recursive rm against a git-tracked file is now evaluated as
    write-tier (recoverable via git checkout HEAD -- <path>) rather than
    dangerous-tier. Untracked files, recursive removes, and paths outside any
    git repo remain dangerous. Hardcoded catastrophic rules
    (deny-rm-catastrophic) still fire regardless of tier.

Documentation

  • docs/threat-model.md updated to reflect the runtime affordances landed
    in T33–T35; the §3 "user's responsibility" framing now points at the
    reporting/warning that doit_check_config and the startup warning
    provide.
  • STABILITY.md snapshot bumped to v0.8.0 with the new
    acknowledged_sibling_servers config field, the per-target rm tier
    table, the project-keyed duration aggregator, and a new pre-1.0 gap
    noting the missing NOTICES / third-party attribution file.

v0.7.0

Choose a tag to compare

@marcelocantos marcelocantos released this 21 Apr 06:00
887bff9

Added

  • doit --help-agent (🎯T28) — prints the CLI reference followed
    by the full embedded agents-guide.md. Closes the pre-existing gap
    noted in the v0.6.0 deferred list so coding agents can pull both
    the CLI reference and the domain guide in a single call without
    having the repo checked out.

    Embedding is compile-time via go:embed from a new top-level doit
    package at the module root — a deliberate workaround for
    go:embed's no-parent-directories rule that avoids a pre-build copy
    step.

Upgrade

Additive; no breaking changes. Safe to upgrade in place.

brew update
brew upgrade marcelocantos/tap/doit

v0.6.0

Choose a tag to compare

@marcelocantos marcelocantos released this 19 Apr 12:17
7825918

Highlights

🎯T27 — Shell-script content-hash approval gate

doit now asks for explicit user approval the first time it sees a
bash foo.sh, sh foo.sh, zsh foo.sh, or ./foo.sh invocation,
keyed by SHA-256 of the script's contents. Subsequent invocations of
the same content bypass the prompt; modifying the script changes the
hash and forces re-approval. Approvals live at
~/.config/doit/script-approvals.yaml.

  • Tier-0 gate: runs before L1/L2/L3.
  • MCP elicitation shows the path, size, hash, and a content preview.
  • Audit log carries script_hash / script_path on every matched run.
  • New MCP tools: doit_approvals_list, doit_approvals_revoke.
  • Scope is deliberately narrow — pipelines, compound commands, and
    bash -c "…" fall through to normal policy.

🎯T26.1 — Time expectations + timeout enforcement

doit_execute and doit_dry_run accept two optional fields:

  • timeout_seconds — hard ceiling. doit kills the entire process
    group on expiry (SIGKILL, exit code 137).
  • expected_duration_seconds — soft estimate, recorded alongside the
    actual duration in the audit log.

New audit fields: expected_duration_ms, timed_out.

🎯T26.2 — L1 rules can inspect time expectations

Starlark rules may opt into request metadata by declaring a third
meta parameter on check. Existing two-parameter rules are
unaffected. The new built-in rule flag-duration-mismatch flags
sleep N commands where N exceeds 2× expected_duration_seconds.

🎯T26.3 — L2 learns per-pattern durations

doit aggregates p50/p95 durations per (cap, subcmd) from the audit
log and persists them at ~/.config/doit/duration-stats.yaml. Two
new bypassable L2 rules use the learned distribution:

  • duration-anomaly — expected_duration_seconds below p50/5 or
    above p95×5 for a pattern with ≥5 samples.
  • timeout-too-short — timeout_seconds below learned p50.

Both are skipped under --retry. Inspect with the new
doit_durations_list MCP tool.

Also in this release

  • 🎯T17 — Engine now treats commands as opaque strings (segments/tiers
    audit fields deprecated, retained for reader compatibility).
  • 🎯T20 — Dead tier code removed.
  • 🎯T22 — Sessions can start when L3 is disabled.
  • 🎯T25 — deny-rm-catastrophic covers system dirs and globs.

Upgrade notes

No breaking changes to the MCP tool surface, engine API, config
schema, or audit log format. Additive only. Safe to upgrade from
v0.5.0 in place.

brew update
brew upgrade marcelocantos/tap/doit

Documentation

  • STABILITY.md — full v0.6.0 interaction surface snapshot
  • agents-guide.md — updated with script-hash trust model, time expectations, and duration learning

v0.5.0

Choose a tag to compare

@marcelocantos marcelocantos released this 12 Apr 00:42
67b8868

Major architectural simplification and feature expansion for doit's MCP server.

Added

  • Work sessions — doit_session_start/_end/_status let an agent declare the scope of a chunk of work. L3 evaluations inside the session reuse the scope for faster, more contextual decisions. Sessions auto-expire.
  • Two-tier L3 cascade — fast triage on sonnet with fall-through to opus for genuinely ambiguous cases. Most commands resolve at the fast tier; opus is reserved for the hard ones. Configured via policy.level3_fast_model and policy.level3_model.
  • L2 policy management — doit_policy_list, doit_policy_delete, doit_policy_review for inspecting and curating learned policy entries.
  • doit_self_audit — detects L1/L2 contradictions, stale entries (90+ days), orphaned Starlark rule IDs, and duplicate L2 coverage.
  • doit_repo_read — allowlisted read-only access to project metadata files (go.mod, Makefile, CLAUDE.md, etc.) for L3 claim verification.
  • doit_check_config — verifies the MCP-first deployment (Bash denied, doit registered) so misconfigurations surface immediately.
  • L3 enabled by default — new installs get the live LLM policy tier out of the box.

Changed

  • Pipeline parser removed — doit no longer tokenises commands into segments at the engine level. The shell handles all composition (&&, |, ;, redirects); commands pass through sh -c unchanged. Segment analysis, where it still happens, is an internal detail of individual policy layers.
  • EvalResult — Segments and Tiers fields removed. The dry-run output no longer displays them.
  • Engine.RecordDecision — signature simplified to (command, decision); cap/subcmd match criteria are derived from the command string directly.
  • L3 rebuilt on claude -p — the persistent claudia Session integration is gone. Every L3 call is now a stateless one-shot claude -p invocation, fixing a hang caused by Claude Code's /clear rolling the session ID.
  • Stderr logging suppressed — doit discards its own log output so MCP clients don't interpret informational messages as errors.

Fixed

  • L3 init race: the engine now constructs L3 synchronously in New, so doit_session_start can no longer fire before L3 is ready.
  • claude -p no longer leaves PTY wrappers or JSONL tailers lying around after a broken session.

Docs

  • STABILITY.md refreshed to a v0.5.0 snapshot covering all 16 MCP tools, session APIs, and the L3 cascade.
  • CLAUDE.md architecture map updated (removed internal/pipeline/, added internal/context/).
  • README and agents-guide.md tool tables completed.

v0.4.0

Choose a tag to compare

@marcelocantos marcelocantos released this 09 Apr 10:09

Changed

  • Error messages updated: Config rule denials now say "(config rule, bypassable)" instead of referencing the removed doit --retry CLI flag
  • agents-guide.md rewritten: Now documents MCP tools (doit_execute, doit_dry_run, etc.) instead of the legacy CLI interface
  • README.md rewritten: Documents MCP server architecture, claude mcp add quick start, MCP tool reference, and elicitation-based policy decisions

Removed

  • All references to legacy CLI syntax (pipelines, unicode operators, --retry, --list, --audit subcommands) from user-facing documentation

v0.3.0

Choose a tag to compare

@marcelocantos marcelocantos released this 08 Apr 15:07

Changed

  • Single binary: doit-mcp and doit consolidated into a single doit MCP server binary. The legacy CLI (internal/cli/) has been removed — all functionality is now MCP tools.

Added

  • MCP elicitation for policy decisions: When the policy engine escalates or hits a bypassable rule, doit presents an interactive dialog to the user with four options: Allow once, Allow always, Deny, Deny always. Replaces the old --retry flag mechanism.
  • Two-phase rule promotion: "Always" choices trigger a follow-up elicitation proposing Starlark rules at narrow/moderate/broad generality levels. Users pick a rule to create or decline.
  • L2 learned policy recording: "Allow always" and "Deny always" decisions are immediately recorded in the L2 policy store for future automatic matching.
  • Admin MCP tools: doit_list_capabilities (with optional tier filter), doit_audit_verify (hash chain integrity check), doit_audit_tail (recent entries)
  • Bypassable field on policy results — propagated from L1 Go rules and Starlark rules through to EvalResult

Removed

  • Legacy CLI binary (cmd/doit/ old entry point)
  • internal/cli/ package (subcommand handlers)
  • --help-agent, --list, --audit, --policy CLI subcommands (replaced by MCP tools)

Dependencies

  • mcp-go updated from v0.44.1 to v0.47.0 (elicitation support)

v0.2.0

Choose a tag to compare

@marcelocantos marcelocantos released this 08 Apr 13:32

Added

  • MCP server (doit-mcp): stdio-transport MCP server as primary agent interface with 4 tools (execute, dry_run, policy_status, approve)
  • Three-level policy engine: L1 deterministic rules → L2 learned patterns → L3 live LLM evaluation
  • Starlark L1 rules: sandboxed, deterministic rule language with embedded test cases and L3→L1 promotion (internal/starlark/)
  • Per-project policy: .doit/config.yaml with tighten-only merge semantics — projects can add rules and restrict tiers but not loosen global policy
  • sh -c execution model: commands execute via shell instead of per-capability runners
  • CI workflow: automated build, vet, and test on push/PR to master
  • Comprehensive test coverage: all core packages tested (internal/cap/, internal/cap/builtin/, internal/cli/, internal/config/, cmd/doit/)

Changed

  • engine/ package is now the primary public API for command evaluation and execution
  • Audit logger enforces max_size_mb config limit (warns and stops writing when exceeded)
  • doit-mcp binary now included in release artifacts alongside doit
  • hasAnyFlag deduplicated (exported from internal/rules/, shared by policy engine)
  • Malformed audit log entries now produce warnings in Tail instead of being silently dropped
  • Token store purges expired tokens on each Validate() call
  • SPDX Apache-2.0 license headers added to all Go source files

Removed

  • Legacy daemon/client/IPC code (~2,454 lines): internal/daemon/, internal/client/, internal/ipc/
  • Pipeline execution engine (internal/pipeline/executor.go); parser retained for policy evaluation
  • DaemonConfig and --daemon CLI subcommand
  • Dead resolveError function and --approved CLI documentation (approval handled by MCP server)

v0.1.0

Choose a tag to compare

@marcelocantos marcelocantos released this 28 Feb 00:24

Added

  • Capability broker mediating all command execution through safety tiers (read, build, write, dangerous)
  • 19 built-in capabilities: cat, chmod, cp, find, git, go, grep, head, ls, make, mkdir, mv, rm, sort, tail, tee, tr, uniq, wc
  • Pipeline syntax with Unicode operators (¦, ›, ‹) that survive unquoted in all shells
  • Compound command operators (&&, ‖, ;) for conditional chaining
  • Per-subcommand tier mapping for git and go
  • Argument-level safety rules (hardcoded and configurable) with --retry bypass
  • SHA-256 hash-chained audit log with integrity verification
  • YAML configuration for tiers, audit path, and custom rules
  • Agent integration guide (doit --help-agent)