Skip to content

Architecture Decision Records

Snodo design decisions extracted from the development audit log and .snodo/bootstrap/decisions.md. Each ADR follows the Nygard format: Title, Status, Context, Decision, Consequences, Alternatives. One page or less each.

ADR Title Date Audit-log anchor
001 PyJWT over custom HMAC signing 2025-05-27 Task 7.7 (tokens.py)
002 Warn withholds approval in policy thresholds 2025-06-01 Policy semantic fix (policy.py)
003 ESCALATE as halt → resolve → resume 2025-05-27 Task 7.10 (loop.py)
004 Constraint predicate framework 2025-05-27 Task 7.8 (predicates/)
005 Protocol-adherence validator from mode profiles 2025-05-27 Task 7.11
006 Severity cap for validators under evaluation 2025-05-31 Task 7.17 (models.py)
007 Coder adapter + code-host provider pattern 2025-05-25 Tasks 4.10, 4.6
008 File-backed session checkpoint over in-memory state 2025-05-27 Task 7.3 (session.py)
009 FastMCP over custom MCP transport 2025-05-25 Task 4.5 (transport.py)
010 GitPython over subprocess for git operations 2025-05-25 Task 4.7 (git.py)
011 Typer over argparse for CLI 2025-05-25 Task 4.8 (main.py)
013 Kleene-closure auto-fix recovery loop 2026-06-28 Recovery driver (closure.py)
014 Trusted-repository threat model and init consent gate 2026-08-21 Threat-model decision (init_cmd.py)
015 Real validation on the MCP path + four-outcome validate_task 2026-08-21 handle_validate_task (server.py)
016 Shared SQLite store for validation-token single-use 2026-08-22 TokenStore (tokens.py)
017 WF1 relaxed to exclusivity on approval-conferring tools 2026-08-23 check_wf1 (verifier.py)
018 Auto-merge task branches on successful completion 2026-08-24 _merge_on_success (run_cmd.py)
019 Phase-aware validator prompts + read tools for repository-content validators 2026-08-24 _phase_frame (llm_validator.py)
020 Wave classification reads ClassifierConfig; classifier model resolved once 2026-08-24 _migrate_wave_classifier_keys (config.py)
021 Recovery builds from the original task, not the previous attempt 2026-08-24 _spawn_recovery_subtask (loop.py)
022 A versioned machine interface (--json) for integrations 2026-08-24 json_output.py + validate_cmd.py
023 Spec-authoring receives only spec-quality critique 2026-08-24 judges_spec (models.py) + _spec_authoring_reentry
024 Environment preparation before task execution 2026-08-24 environment.py + governance.py
025 Unborn-HEAD worktree creation fails loud, never degrades to no isolation 2026-08-24 create_worktree + setup_for_task (worktree.py)
026 Protocol and governance state protected from agent tool-surface mutation 2026-08-24 workspace.py + git.py + coders/
027 In-place coder .snodo/ mutations are detected and halt as a blocker 2026-08-25 coders/base.py + engine/loop.py
028 Post-execute acceptance validator judges artifacts against the task's acceptance criteria 2026-08-25 validators/acceptance.py + validators/runner.py
029 Per-mode max_recovery_depth override 2026-08-25 resolve_mode_setting (models.py)
030 In-place coder adapters own the commit, so the review channel is the artifact channel 2026-08-26 coders/base.py + coders/opencode_adapter.py
031 First-class verification events in audit trail and blocking unverified merges 2026-08-26 quality.py + run_cmd.py
032 Patch coverage measurement over modified lines 2026-08-26 patch_coverage.py + ci.yml
033 Tool loop repeat read memory and result preservation 2026-08-26 litellm.py + llm_validator.py
034 The opencode coder path is experimental, not supported 2026-08-26 init_cmd.py + docs/protocol.md
035 Declared coder-adapter capability interface; "coder produced nothing" is always a fault 2026-08-26 core/interfaces.py + engine/nodes/executor.py
036 Operator human review tracking via audit log events 2026-08-26 task_cmd.py + audit.py
037 CHANGELOG.md merges with merge=union, not fragment files 2026-08-27 .gitattributes + test_changelog_union_merge.py
038 The Orchestrator Role & Audit Trail Contract 2026-08-27 docs/decisions/038-orchestrator-role-and-audit-contract.md
039 Validation is independent of the coder; engine builds its LLM client from configuration 2026-08-30 engine/loop.py (GraphBuilder.__init__)