anvil-state 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. anvil_state-0.1.1/.gitignore +25 -0
  2. anvil_state-0.1.1/PKG-INFO +46 -0
  3. anvil_state-0.1.1/README.md +20 -0
  4. anvil_state-0.1.1/anvil +27 -0
  5. anvil_state-0.1.1/anvil-mcp +24 -0
  6. anvil_state-0.1.1/pyproject.toml +124 -0
  7. anvil_state-0.1.1/src/anvil/__init__.py +7 -0
  8. anvil_state-0.1.1/src/anvil/_data/AGENTS.md +85 -0
  9. anvil_state-0.1.1/src/anvil/_data/packaging/codex/automations/README.md +21 -0
  10. anvil_state-0.1.1/src/anvil/_data/packaging/codex/automations/anvil-sync-reconcile/automation.toml +13 -0
  11. anvil_state-0.1.1/src/anvil/_data/packaging/codex/automations/anvil-work-queue/automation.toml +13 -0
  12. anvil_state-0.1.1/src/anvil/claims/__init__.py +0 -0
  13. anvil_state-0.1.1/src/anvil/claims/manager.py +913 -0
  14. anvil_state-0.1.1/src/anvil/claims/metrics.py +191 -0
  15. anvil_state-0.1.1/src/anvil/claims/stale.py +111 -0
  16. anvil_state-0.1.1/src/anvil/cli/__init__.py +142 -0
  17. anvil_state-0.1.1/src/anvil/cli/__main__.py +4 -0
  18. anvil_state-0.1.1/src/anvil/cli/_helpers.py +501 -0
  19. anvil_state-0.1.1/src/anvil/cli/_json.py +146 -0
  20. anvil_state-0.1.1/src/anvil/cli/_sample.py +458 -0
  21. anvil_state-0.1.1/src/anvil/cli/backup.py +165 -0
  22. anvil_state-0.1.1/src/anvil/cli/claim.py +652 -0
  23. anvil_state-0.1.1/src/anvil/cli/claim_guard.py +218 -0
  24. anvil_state-0.1.1/src/anvil/cli/conflicts.py +139 -0
  25. anvil_state-0.1.1/src/anvil/cli/describe.py +255 -0
  26. anvil_state-0.1.1/src/anvil/cli/doctor.py +783 -0
  27. anvil_state-0.1.1/src/anvil/cli/drift.py +228 -0
  28. anvil_state-0.1.1/src/anvil/cli/gate_check.py +248 -0
  29. anvil_state-0.1.1/src/anvil/cli/graph.py +408 -0
  30. anvil_state-0.1.1/src/anvil/cli/hooks.py +414 -0
  31. anvil_state-0.1.1/src/anvil/cli/init_status.py +562 -0
  32. anvil_state-0.1.1/src/anvil/cli/install.py +1106 -0
  33. anvil_state-0.1.1/src/anvil/cli/mcp_config.py +268 -0
  34. anvil_state-0.1.1/src/anvil/cli/migrate.py +565 -0
  35. anvil_state-0.1.1/src/anvil/cli/migrate_workspace.py +158 -0
  36. anvil_state-0.1.1/src/anvil/cli/notify_digest.py +69 -0
  37. anvil_state-0.1.1/src/anvil/cli/packet_apply.py +994 -0
  38. anvil_state-0.1.1/src/anvil/cli/plan.py +1699 -0
  39. anvil_state-0.1.1/src/anvil/cli/prd.py +643 -0
  40. anvil_state-0.1.1/src/anvil/cli/proof.py +125 -0
  41. anvil_state-0.1.1/src/anvil/cli/replay.py +103 -0
  42. anvil_state-0.1.1/src/anvil/cli/run_workflow.py +94 -0
  43. anvil_state-0.1.1/src/anvil/cli/scan.py +299 -0
  44. anvil_state-0.1.1/src/anvil/cli/sync.py +1608 -0
  45. anvil_state-0.1.1/src/anvil/clock.py +49 -0
  46. anvil_state-0.1.1/src/anvil/config.py +1095 -0
  47. anvil_state-0.1.1/src/anvil/context/__init__.py +0 -0
  48. anvil_state-0.1.1/src/anvil/context/packet_metrics.py +155 -0
  49. anvil_state-0.1.1/src/anvil/context/packets.py +630 -0
  50. anvil_state-0.1.1/src/anvil/git_ops/__init__.py +0 -0
  51. anvil_state-0.1.1/src/anvil/git_ops/branch.py +249 -0
  52. anvil_state-0.1.1/src/anvil/git_ops/worktree.py +102 -0
  53. anvil_state-0.1.1/src/anvil/mcp_server.py +2962 -0
  54. anvil_state-0.1.1/src/anvil/planning/__init__.py +21 -0
  55. anvil_state-0.1.1/src/anvil/planning/_plan_helpers.py +498 -0
  56. anvil_state-0.1.1/src/anvil/planning/decisions.py +672 -0
  57. anvil_state-0.1.1/src/anvil/planning/inference.py +550 -0
  58. anvil_state-0.1.1/src/anvil/planning/llm.py +839 -0
  59. anvil_state-0.1.1/src/anvil/planning/llm_planner.py +672 -0
  60. anvil_state-0.1.1/src/anvil/planning/scoring.py +799 -0
  61. anvil_state-0.1.1/src/anvil/planning/template.py +1331 -0
  62. anvil_state-0.1.1/src/anvil/py.typed +0 -0
  63. anvil_state-0.1.1/src/anvil/review/__init__.py +19 -0
  64. anvil_state-0.1.1/src/anvil/review/gates.py +389 -0
  65. anvil_state-0.1.1/src/anvil/scan/__init__.py +35 -0
  66. anvil_state-0.1.1/src/anvil/scan/model.py +385 -0
  67. anvil_state-0.1.1/src/anvil/scan/prd_draft.py +199 -0
  68. anvil_state-0.1.1/src/anvil/signing.py +173 -0
  69. anvil_state-0.1.1/src/anvil/state/__init__.py +15 -0
  70. anvil_state-0.1.1/src/anvil/state/backend.py +333 -0
  71. anvil_state-0.1.1/src/anvil/state/durable.py +94 -0
  72. anvil_state-0.1.1/src/anvil/state/hashing.py +76 -0
  73. anvil_state-0.1.1/src/anvil/state/models.py +849 -0
  74. anvil_state-0.1.1/src/anvil/state/payloads.py +875 -0
  75. anvil_state-0.1.1/src/anvil/state/schema.py +235 -0
  76. anvil_state-0.1.1/src/anvil/state/snapshot.py +135 -0
  77. anvil_state-0.1.1/src/anvil/state/sqlite.py +4357 -0
  78. anvil_state-0.1.1/src/anvil/state/transitions.py +654 -0
  79. anvil_state-0.1.1/src/anvil/sync/__init__.py +75 -0
  80. anvil_state-0.1.1/src/anvil/sync/clients/__init__.py +25 -0
  81. anvil_state-0.1.1/src/anvil/sync/clients/gh_cli.py +465 -0
  82. anvil_state-0.1.1/src/anvil/sync/clients/github_http.py +411 -0
  83. anvil_state-0.1.1/src/anvil/sync/errors.py +75 -0
  84. anvil_state-0.1.1/src/anvil/sync/provider.py +400 -0
  85. anvil_state-0.1.1/src/anvil/sync/providers/__init__.py +21 -0
  86. anvil_state-0.1.1/src/anvil/sync/providers/github_issues.py +651 -0
  87. anvil_state-0.1.1/src/anvil/sync/reconciliation.py +972 -0
  88. anvil_state-0.1.1/src/anvil/sync/recorded.py +258 -0
  89. anvil_state-0.1.1/src/anvil/sync/registry.py +99 -0
  90. anvil_state-0.1.1/src/anvil/workflows/__init__.py +13 -0
  91. anvil_state-0.1.1/src/anvil/workflows/fanout.py +125 -0
  92. anvil_state-0.1.1/src/anvil/workflows/parse.py +129 -0
  93. anvil_state-0.1.1/src/anvil/workflows/proof.py +41 -0
  94. anvil_state-0.1.1/src/anvil/workflows/runner.py +211 -0
  95. anvil_state-0.1.1/src/anvil/workflows/schema.py +43 -0
  96. anvil_state-0.1.1/src/anvil/workflows/tasks.py +188 -0
  97. anvil_state-0.1.1/uv.lock +2181 -0
@@ -0,0 +1,25 @@
1
+ # Python virtualenv (uv sync materializes this under bin/)
2
+ .venv/
3
+ bin/.venv/
4
+
5
+ # Python bytecode / build artifacts
6
+ __pycache__/
7
+ *.pyc
8
+ dist/
9
+ *.egg-info/
10
+
11
+ # Test / tooling caches
12
+ .pytest_cache/
13
+ .mypy_cache/
14
+ .ruff_cache/
15
+ .coverage
16
+ bin/.coverage
17
+
18
+ # anvil runtime state (created when running the CLI, tests, or benchmarks)
19
+ .anvil/
20
+ bin/.anvil/
21
+ packets/
22
+
23
+ # Agent build scratch space — never commit
24
+ .anvil-build/
25
+ docs/plans/agent-*-status.md
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: anvil-state
3
+ Version: 0.1.1
4
+ Summary: Local-first project state engine: turn rough ideas and PRDs into reviewed, lockable, evidence-backed work packets that humans and AI agents can coordinate on without conflicts.
5
+ Author: Sekou Doumbouya
6
+ License: MIT
7
+ Keywords: agent-coordination,claims,evidence-based,llm-work-packets,local-first,mcp,project-state,runtime-neutral,sqlite,terraform-for-work
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: anthropic>=0.30
10
+ Requires-Dist: cryptography>=42
11
+ Requires-Dist: fastmcp
12
+ Requires-Dist: httpx>=0.27
13
+ Requires-Dist: pydantic>=2.6
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: typer>=0.12
16
+ Provides-Extra: all-providers
17
+ Requires-Dist: anthropic[bedrock]>=0.30; extra == 'all-providers'
18
+ Requires-Dist: openai>=1.0; extra == 'all-providers'
19
+ Provides-Extra: bedrock
20
+ Requires-Dist: anthropic[bedrock]>=0.30; extra == 'bedrock'
21
+ Provides-Extra: custom
22
+ Requires-Dist: openai>=1.0; extra == 'custom'
23
+ Provides-Extra: s3
24
+ Requires-Dist: boto3>=1.26; extra == 's3'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # anvil-state
28
+
29
+ Local-first project state engine: turn rough ideas and PRDs into reviewed,
30
+ lockable, evidence-backed work packets that humans and AI coding agents can
31
+ coordinate on without conflicts.
32
+
33
+ `anvil-state` installs the `anvil` CLI and the `anvil-mcp` MCP server.
34
+
35
+ ```bash
36
+ uv tool install anvil-state # or: pipx install anvil-state
37
+ anvil --help
38
+ anvil install <harness> # wire anvil into Codex, Cursor, VS Code, ...
39
+ ```
40
+
41
+ The MCP server (`anvil-mcp`) exposes anvil's tool surface to any MCP-capable
42
+ harness. `anvil install <harness>` writes the MCP config and instruction file for
43
+ a target harness (idempotent, backed up, reversible with `--rollback`).
44
+
45
+ Full documentation, the cross-harness install guide, and the Claude Code plugin
46
+ live in the repository: https://github.com/fakoli/anvil
@@ -0,0 +1,20 @@
1
+ # anvil-state
2
+
3
+ Local-first project state engine: turn rough ideas and PRDs into reviewed,
4
+ lockable, evidence-backed work packets that humans and AI coding agents can
5
+ coordinate on without conflicts.
6
+
7
+ `anvil-state` installs the `anvil` CLI and the `anvil-mcp` MCP server.
8
+
9
+ ```bash
10
+ uv tool install anvil-state # or: pipx install anvil-state
11
+ anvil --help
12
+ anvil install <harness> # wire anvil into Codex, Cursor, VS Code, ...
13
+ ```
14
+
15
+ The MCP server (`anvil-mcp`) exposes anvil's tool surface to any MCP-capable
16
+ harness. `anvil install <harness>` writes the MCP config and instruction file for
17
+ a target harness (idempotent, backed up, reversible with `--rollback`).
18
+
19
+ Full documentation, the cross-harness install guide, and the Claude Code plugin
20
+ live in the repository: https://github.com/fakoli/anvil
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # anvil — shell wrapper that bridges bin/src/ Python source to Claude Code
3
+ # skills, hooks, and the shell. Ensures uv is synced (idempotent) then execs the
4
+ # CLI module so signals propagate cleanly to the Python process.
5
+
6
+ # Preserve caller's cwd so the CLI sees the directory the user actually invoked
7
+ # from. Without this, `anvil init` would scaffold .anvil/ inside
8
+ # the plugin's bin/ instead of the user's project.
9
+ ORIGINAL_PWD="$PWD"
10
+ BIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+
12
+ if ! command -v uv > /dev/null 2>&1; then
13
+ printf 'anvil: uv is required: https://docs.astral.sh/uv/getting-started/installation/\n' >&2
14
+ exit 127
15
+ fi
16
+
17
+ # Sync only when uv.lock is missing, pyproject.toml is newer than .venv,
18
+ # or uv.lock is newer than .venv (covers the `git pull` case where only the
19
+ # lock file moves). File-age based, fully idempotent — no cat/grep involved.
20
+ (cd "$BIN_DIR" && {
21
+ if [ ! -f uv.lock ] || [ pyproject.toml -nt .venv ] || [ uv.lock -nt .venv ]; then
22
+ uv sync --quiet
23
+ fi
24
+ })
25
+
26
+ cd "$ORIGINAL_PWD" || exit 1
27
+ exec uv run --quiet --project "$BIN_DIR" python -m anvil.cli "$@"
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # anvil-mcp — shell wrapper for the MCP server entry point.
3
+ # anvil.mcp_server landed in Phase 6 and registers 13 tools via FastMCP.
4
+
5
+ # Preserve caller's cwd; see bin/anvil for the rationale.
6
+ ORIGINAL_PWD="$PWD"
7
+ BIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+
9
+ if ! command -v uv > /dev/null 2>&1; then
10
+ printf 'anvil-mcp: uv is required: https://docs.astral.sh/uv/getting-started/installation/\n' >&2
11
+ exit 127
12
+ fi
13
+
14
+ # Sync only when uv.lock is missing, pyproject.toml is newer than .venv,
15
+ # or uv.lock is newer than .venv (covers the `git pull` case where only the
16
+ # lock file moves). File-age based, fully idempotent — no cat/grep involved.
17
+ (cd "$BIN_DIR" && {
18
+ if [ ! -f uv.lock ] || [ pyproject.toml -nt .venv ] || [ uv.lock -nt .venv ]; then
19
+ uv sync --quiet
20
+ fi
21
+ })
22
+
23
+ cd "$ORIGINAL_PWD" || exit 1
24
+ exec uv run --quiet --project "$BIN_DIR" python -m anvil.mcp_server "$@"
@@ -0,0 +1,124 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "anvil-state"
7
+ version = "0.1.1"
8
+ description = "Local-first project state engine: turn rough ideas and PRDs into reviewed, lockable, evidence-backed work packets that humans and AI agents can coordinate on without conflicts."
9
+ # Build-root-local README. `../README.md` escaped the bin/ build root and broke
10
+ # `uv build` (sdist->wheel: "Readme file does not exist: ../README.md"). This is
11
+ # the package-focused PyPI long description; the full repo README stays at root.
12
+ readme = "README.md"
13
+ requires-python = ">=3.11"
14
+ license = { text = "MIT" }
15
+ authors = [
16
+ { name = "Sekou Doumbouya" },
17
+ ]
18
+ keywords = [
19
+ "agent-coordination",
20
+ "claims",
21
+ "evidence-based",
22
+ "llm-work-packets",
23
+ "local-first",
24
+ "mcp",
25
+ "project-state",
26
+ "runtime-neutral",
27
+ "sqlite",
28
+ "terraform-for-work",
29
+ ]
30
+ dependencies = [
31
+ "typer>=0.12",
32
+ "pydantic>=2.6",
33
+ "fastmcp",
34
+ "anthropic>=0.30",
35
+ "PyYAML>=6.0",
36
+ "httpx>=0.27",
37
+ # Ed25519 signing for portable ProofArtifacts (B48 part 2). Already resolved
38
+ # transitively (authlib/joserfc); pinned explicitly so a transitive bump
39
+ # can't silently remove the signing primitive the trust layer depends on.
40
+ "cryptography>=42",
41
+ ]
42
+
43
+ # Optional extras enable additional LLM providers (v1.17.0). The default
44
+ # install only depends on `anthropic` for the direct API path. Users who
45
+ # want Amazon Bedrock or an OpenAI-compatible custom endpoint opt in by
46
+ # installing the corresponding extra:
47
+ #
48
+ # pip install 'anvil-state[bedrock]' # adds anthropic[bedrock] (boto3)
49
+ # pip install 'anvil-state[custom]' # adds openai for /v1/chat/completions
50
+ # pip install 'anvil-state[bedrock,custom]' # both
51
+ # pip install 'anvil-state[all-providers]' # convenience alias
52
+ #
53
+ # Keeping these optional avoids pulling boto3 (~70MB of transitive deps)
54
+ # and the openai SDK onto every install — most users only need direct API.
55
+ [project.optional-dependencies]
56
+ bedrock = ["anthropic[bedrock]>=0.30"]
57
+ custom = ["openai>=1.0"]
58
+ s3 = ["boto3>=1.26"]
59
+ all-providers = [
60
+ "anthropic[bedrock]>=0.30",
61
+ "openai>=1.0",
62
+ ]
63
+
64
+ [project.scripts]
65
+ anvil = "anvil.cli:app"
66
+ # The MCP server as a real console script so a wheel install (uv tool/pipx/pip)
67
+ # exposes a launchable `anvil-mcp` on PATH. Without this, every emitted MCP config
68
+ # pointed at the bin/anvil-mcp bash wrapper, which a wheel does not ship.
69
+ anvil-mcp = "anvil.mcp_server:main"
70
+
71
+ [dependency-groups]
72
+ dev = [
73
+ "pytest>=8",
74
+ "pytest-cov>=5",
75
+ "ruff>=0.5",
76
+ "mypy>=1.10",
77
+ "types-pyyaml>=6.0.12.20260518",
78
+ # HTTP mocker: respx mocks httpx (the transport our GitHub HTTP client uses).
79
+ "respx>=0.21",
80
+ ]
81
+
82
+ [tool.hatch.build.targets.wheel]
83
+ # Ships src/anvil with its non-.py package data (py.typed + _data/AGENTS.md +
84
+ # _data/packaging/codex/automations). The installer reads _data via
85
+ # importlib.resources, so a wheel MUST carry it — do not add an exclude that drops
86
+ # _data. Guarded by tests/test_install_manifests.py::test_built_wheel_is_self_sufficient.
87
+ packages = ["src/anvil"]
88
+
89
+ [tool.ruff]
90
+ line-length = 100
91
+ target-version = "py311"
92
+
93
+ [tool.ruff.lint]
94
+ select = ["E", "F", "I", "B", "UP"]
95
+
96
+ [tool.ruff.lint.per-file-ignores]
97
+ # Tests routinely embed long SQL strings, assertion messages, and snapshot
98
+ # literals where readability beats wrapping.
99
+ "../tests/**" = ["E501"]
100
+
101
+ [tool.mypy]
102
+ strict = true
103
+ python_version = "3.11"
104
+
105
+ [[tool.mypy.overrides]]
106
+ # Tests intentionally use **dict factory patterns, assert against frozen
107
+ # dataclasses, and pass deliberately-wrong types to verify error paths.
108
+ # pytest's own conventions (fixtures, monkeypatch, parameterize) further
109
+ # undermine static typing. Keep strict on src; relax on tests.
110
+ module = "tests.*"
111
+ disallow_untyped_defs = false
112
+ disallow_incomplete_defs = false
113
+ disallow_untyped_calls = false
114
+ disallow_any_generics = false
115
+ warn_return_any = false
116
+ no_implicit_reexport = false
117
+ ignore_errors = true
118
+
119
+ [tool.pytest.ini_options]
120
+ testpaths = ["../tests"]
121
+ addopts = "-m 'not live_github'"
122
+ markers = [
123
+ "live_github: tests that hit the real GitHub API (require ANVIL_TEST_GH_TOKEN env)",
124
+ ]
@@ -0,0 +1,7 @@
1
+ """anvil — local-first project state engine for humans and AI agents."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __version__ = "0.1.1"
6
+
7
+ __all__ = ["__version__"]
@@ -0,0 +1,85 @@
1
+ # AGENTS.md — Anvil
2
+
3
+ Anvil is a local-first, backend-neutral **project-state engine**: it turns PRDs
4
+ into reviewed, lockable, evidence-backed work packets that humans and AI agents
5
+ can coordinate on without conflicts. State lives in SQLite under
6
+ `.anvil/` (event-sourced; `events.jsonl` is the log). Two equivalent surfaces:
7
+
8
+ - **CLI** — `bin/anvil <command>` (single mutator, no harness dependency).
9
+ - **MCP** — `bin/anvil-mcp` (24 FastMCP stdio tools). Run
10
+ `anvil mcp-config <your-client>` to print client-specific config.
11
+
12
+ Both resolve the project via `ANVIL_ROOT` env var, else the current directory.
13
+ Every read command supports `--json` for a `{"ok":…,"command":…,"data":…}`
14
+ envelope. **Prefer the MCP tool if your harness has MCP; otherwise use the CLI
15
+ command in the same row — they are equivalent.**
16
+
17
+ ## The standalone loop
18
+
19
+ init → author/parse PRD → review → plan + score → claim → work packet →
20
+ submit evidence → apply review verdict.
21
+
22
+ ```bash
23
+ anvil init # scaffold .anvil/
24
+ # author .anvil/prd.md (see docs/prd-template.md), then:
25
+ anvil prd parse && anvil review prd approve
26
+ anvil plan && anvil score
27
+ anvil next # pick a ready task
28
+ anvil claim T001 # lease it, get a branch
29
+ anvil packet T001 # work packet; do the work
30
+ anvil submit T001 --evidence …
31
+ anvil apply T001 # apply the review verdict
32
+ ```
33
+
34
+ ## Capabilities (MCP tool ⇄ CLI command)
35
+
36
+ | Capability | MCP tool | CLI command |
37
+ |---|---|---|
38
+ | Init project | `init_project` | `anvil init` |
39
+ | Project status | `get_project_status` | `anvil status` |
40
+ | Project summary | `get_project_summary` | `anvil status --json` |
41
+ | Parse PRD | `parse_prd` | `anvil prd parse` |
42
+ | Review PRD | `review_prd` | `anvil review prd …` |
43
+ | Plan tasks | `plan_tasks` | `anvil plan` |
44
+ | Score tasks | `score_tasks` | `anvil score` |
45
+ | Review tasks | `review_tasks` | `anvil review tasks …` |
46
+ | Apply review decision | `apply_review_decision` | `anvil apply` |
47
+ | Find open decisions | `find_decisions` | `anvil prd find-decisions` |
48
+ | List tasks | `list_tasks` | `anvil list` |
49
+ | Show one task | `get_task` | `anvil show <id>` |
50
+ | Next ready task | `get_next_task` | `anvil next` |
51
+ | Claim task | `claim_task` | `anvil claim <id>` |
52
+ | Release claim | `release_task` | `anvil release <id>` |
53
+ | Renew claim lease | `renew_claim` | `anvil renew <id>` |
54
+ | Work packet | `generate_work_packet` | `anvil packet <id>` |
55
+ | Submit progress | `submit_progress` | `anvil submit <id> --progress …` |
56
+ | Submit evidence | `submit_completion_evidence` | `anvil submit <id> --evidence …` |
57
+ | Update task status | `update_task_status` | (via claim/submit/apply flow) |
58
+ | File-conflict check | `check_conflicts` | `anvil conflicts` |
59
+ | Dependency graph | `get_dependency_graph` | `anvil graph` / `anvil deps` |
60
+ | Edit dependencies | `edit_dependencies` | `anvil deps --add/--remove` |
61
+ | Describe surface | `describe_surface` | `anvil describe` |
62
+
63
+ (Exact tool names mirror `bin/src/anvil/mcp_server.py`; CLI commands mirror
64
+ `bin/src/anvil/cli/__init__.py`. Run `anvil describe --json` for the live list.)
65
+
66
+ ### Execution vs planning surface (MCP)
67
+
68
+ To keep the per-turn context lean, the MCP server exposes only the **14
69
+ execution tools** by default — the turn-to-turn loop (next/claim/packet/submit/
70
+ status/conflicts/deps). The **10 one-shot planning tools** (`init_project`,
71
+ `parse_prd`, `review_prd`, `plan_tasks`, `score_tasks`, `review_tasks`,
72
+ `apply_review_decision`, `edit_dependencies`, `find_decisions`,
73
+ `describe_surface`) are **hidden by default** and re-appear when the server is
74
+ started with **`ANVIL_MCP_PLANNING=1`** (or `true`/`yes`/`on`). Nothing is
75
+ removed — every capability stays reachable via the CLI command in the same row,
76
+ and the full 24-tool surface returns the moment the env flag is set. Use it for
77
+ the planning phase; the steady-state execution loop needs none of the 10.
78
+
79
+ ## Notes
80
+ - Claude Code adds SessionStart/PreToolUse/PostToolUse **hooks**; these are
81
+ Claude-Code-only and have no cross-harness equivalent. Every capability is
82
+ still reachable via the CLI/MCP rows above without them.
83
+ - `uv` is the only prerequisite; the wrappers self-sync on first run.
84
+ - Distribution: `anvil install <harness> --write` writes the MCP config and
85
+ drops this `AGENTS.md` where the harness reads it (dry-run by default).
@@ -0,0 +1,21 @@
1
+ # Anvil automations for Codex
2
+
3
+ Codex [automations](https://developers.openai.com/codex) are scheduled agent runs
4
+ defined by `~/.codex/automations/<id>/automation.toml` (cron `rrule`, a `model`,
5
+ an `execution_environment`, and a `prompt`). They are how anvil delivers
6
+ **longer-running, recurring work** — the same project state, worked on a schedule.
7
+
8
+ These are **templates**. `anvil install codex --write --automations` materializes
9
+ them into `~/.codex/automations/<template>-<project-basename>-<hash8>/` (e.g.
10
+ `anvil-work-queue-myrepo-3f9a1c20`) with the project path and timestamps filled in,
11
+ **`status = "PAUSED"`** so nothing runs until you review and activate it in the
12
+ Codex app (Automations). Without `--write` the command is a dry-run that only
13
+ previews what it would create. Remove them with `anvil install codex --rollback`.
14
+
15
+ | Template | What it does |
16
+ |---|---|
17
+ | `anvil-work-queue` | Claim + execute the next ready anvil task to passing evidence, one PR per task. |
18
+ | `anvil-sync-reconcile` | Run `anvil sync` to detect (and, when safe, fix) state drift. |
19
+
20
+ Placeholders substituted at install: `{{ID}}` (dir name), `{{CWDS}}` (JSON-quoted
21
+ project root), `{{TS}}` (epoch-ms timestamp).
@@ -0,0 +1,13 @@
1
+ version = 1
2
+ id = "{{ID}}"
3
+ kind = "cron"
4
+ name = "Anvil — reconcile state"
5
+ prompt = "Run anvil's state reconciliation for this project. Run `anvil sync` (read-only) to detect drift between the SQLite state, the filesystem (packets/, evidence buffer, worktrees), and git (branches, claims). Report any orphan branches, stale claims, orphan packets, or missing sync mappings. Only apply fixes with `anvil sync --fix --yes` when the drift is clearly safe to remediate; otherwise summarize the drift and recommend next actions."
6
+ status = "PAUSED"
7
+ rrule = "FREQ=WEEKLY;BYDAY=MO;BYHOUR=8;BYMINUTE=0"
8
+ model = "gpt-5-codex"
9
+ reasoning_effort = "high"
10
+ execution_environment = "worktree"
11
+ cwds = [{{CWDS}}]
12
+ created_at = {{TS}}
13
+ updated_at = {{TS}}
@@ -0,0 +1,13 @@
1
+ version = 1
2
+ id = "{{ID}}"
3
+ kind = "cron"
4
+ name = "Anvil — work the task queue"
5
+ prompt = "Work the anvil task queue for this project. Use the anvil MCP tools (or the `anvil` CLI): find the next ready task (get_next_task / `anvil next`), claim it, fetch its work packet, implement it to satisfy the acceptance criteria, run the verification commands, then submit completion evidence — never mark work complete without passing evidence. If no task is ready, say so and stop. Work in the provided worktree; open one PR per task and do not merge."
6
+ status = "PAUSED"
7
+ rrule = "FREQ=WEEKLY;BYDAY=MO,WE,FR;BYHOUR=9;BYMINUTE=0"
8
+ model = "gpt-5-codex"
9
+ reasoning_effort = "high"
10
+ execution_environment = "worktree"
11
+ cwds = [{{CWDS}}]
12
+ created_at = {{TS}}
13
+ updated_at = {{TS}}
File without changes