Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ uv run pytest # full suite
uv run pytest tests/test_<module>.py -v # one module
```

Run `uv run pytest --collect-only -q | tail -1` for the live test count (last refresh: 3,199 tests collected, 2026-06-03). New backend protocols add ~25 conformance + ~10 impl-specific tests. New features ship with tests. Migration-shaped PRs need parameterized fixture tests across the backend protocol — the conformance suite is what keeps the protocol honest.
Run `uv run pytest --collect-only -q | tail -1` for the live test count (last refresh: 3,232 tests collected, 2026-06-04). New backend protocols add ~25 conformance + ~10 impl-specific tests. New features ship with tests. Migration-shaped PRs need parameterized fixture tests across the backend protocol — the conformance suite is what keeps the protocol honest.

### Releases + SemVer

Expand Down Expand Up @@ -292,7 +292,7 @@ If the project ever needs to optimize differently, `docs/methodology.md` is the
| Doc | Purpose |
|-----|---------|
| `docs/architecture.md` | Mental model in diagrams. Read first. |
| `docs/spec/01-...33-persona-backend.md` | Locked spec (33 docs today, 31 locked + 2 drafts at spec/26 (cascade bundle) and spec/30 (responsibility audit)). The product. |
| `docs/spec/01-...36-mcp-server-registry-backend.md` | Locked spec (35 docs today, 31 locked + 4 drafts at spec/26 (cascade bundle), spec/30 (responsibility audit), spec/35 (init wizard), and spec/36 (MCPServerRegistryBackend)). The product. |
| `docs/implementation/` | Build guides per runtime (cron, Claude skill, dashboard) |
| `docs/deployment/versioning.md`, `upgrading.md` | SemVer + operator runbook |
| `docs/deployment/release-runbook.md` | Maintainer `/ship` runbook: two-mode workflow + manual surface check |
Expand Down Expand Up @@ -341,7 +341,7 @@ These are not forbidden forever — they're explicitly deferred with rationale.

## Status

**v0.13.0, alpha, PUBLIC.** Core runtime stable. Test suite: run `uv run pytest --collect-only -q | tail -1` for the live count (last refresh: 3,199 tests collected, 2026-06-03). Capability-gated skips fall into four buckets — ToolRegistry conformance (filesystem-shape + `supports_uninstall=False` variants), AgentProfile (skill-content + filesystem-shape on SQLite), cross-process Redis (require real Redis instead of fakeredis), and judge-conformance dispatch (LLM-only + PolicyJudge concurrent-evaluate). Full CI runs against `uv sync --extra dev --extra openai --extra validation --extra redis`. **Eleven backend protocols shipped**:
**v0.13.0, alpha, PUBLIC.** Core runtime stable. Test suite: run `uv run pytest --collect-only -q | tail -1` for the live count (last refresh: 3,232 tests collected, 2026-06-04). Capability-gated skips fall into four buckets — ToolRegistry conformance (filesystem-shape + `supports_uninstall=False` variants), AgentProfile (skill-content + filesystem-shape on SQLite), cross-process Redis (require real Redis instead of fakeredis), and judge-conformance dispatch (LLM-only + PolicyJudge concurrent-evaluate). Full CI runs against `uv sync --extra dev --extra openai --extra validation --extra redis`. **Eleven backend protocols shipped**:

- **MemoryBackend** (PR #57) — filesystem reference impl + conformance suite.
- **LLMBackend** (#87) — Anthropic + OpenAI + Moonshot reference impls, registered at framework import; conformance suite parametrizes across all three.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ Start at [`docs/README.md`](docs/README.md) for the spec entry point. The locked
- [33 — PersonaBackend Protocol](docs/spec/33-persona-backend.md) — persona ownership, snapshot/restore, `persona.link.md` format
- [34 — CorpusBackend Protocol](docs/spec/34-corpus-backend.md) — wiki/raw corpus protocol; filesystem + SQLite (FTS5) reference impls; GB-scale indexed full-text search
- [35 — init wizard](docs/spec/35-init-wizard.md) — `atomic-agents init` on-ramp; template scaffolding + Add-to-it merge; CI-friendly `--from-template` (RFC)
- [36 — MCPServerRegistryBackend Protocol](docs/spec/36-mcp-server-registry-backend.md) — MCP server catalog + install/audit; `FilesystemMCPServerRegistryBackend` reference impl; `atomic-agents mcp-registry` CLI (DRAFT, PR 1 of 5)
- [36 — MCPServerRegistryBackend Protocol](docs/spec/36-mcp-server-registry-backend.md) — MCP server catalog + install/audit; `FilesystemMCPServerRegistryBackend` reference impl; `atomic-agents mcp-registry` CLI (DRAFT, PR 3 of 5)

Each spec doc is locked when the implementation matches and tests pass. Spec changes that imply implementation changes get filed as GitHub issues. **Spec docs separate shipped behavior from explicit future / deferred boundaries** — sections that describe behavior not yet implemented are explicitly marked as such, not silently aspirational.

Expand Down Expand Up @@ -282,7 +282,7 @@ Same pattern for OpenAI (`atomic-agents-openai`) and Moonshot (`atomic-agents-mo
## Repository structure

- `atomic_agents/` — the Python package (runtime in `agent.py`; backend protocols in `memory/`, `_llm.py`, `_locks.py`, `_costs.py`, etc.; CLI in `cli.py`; preflight in `doctor.py`)
- `tests/` 3199 tests collected (3141 passing + 58 skipped), Python 3.11 + 3.12 matrix
- `tests/` 3,232 tests collected, Python 3.11 + 3.12 matrix
- `docs/` — [spec entry point](docs/README.md), [`architecture.md`](docs/architecture.md), [`spec/`](docs/spec/) (31 locked docs + 4 RFCs/DRAFTs), [`deployment/`](docs/deployment/) (8 operator runbooks), [`samples/caldwell/`](docs/samples/caldwell/) (complete worked example), [`GOVERNANCE.md`](docs/GOVERNANCE.md), [`TENSIONS.md`](docs/TENSIONS.md), [`methodology.md`](docs/methodology.md)
- `extras/` — operational templates (Claude Code skill wrappers, macOS LaunchAgent plists, cron examples)

Expand Down Expand Up @@ -313,4 +313,4 @@ Before opening a PR, read [`CLAUDE.md`](CLAUDE.md) (the project's design ethos a

## Status

**v0.13.0, alpha.** Core runtime stable. 3199 tests collected (3141 passing + 58 skipped) on Python 3.11 / 3.12. Eleven of twelve backend protocols shipped (see the backend protocols table above); `MCPServerRegistryBackend` planned. The surface stabilizes at v1.0. Pre-1.0 — Minor releases may contain breaking changes (see [`docs/deployment/versioning.md`](docs/deployment/versioning.md)). Single-maintainer project; reference implementation anyone can use, fork, or extend.
**v0.13.0, alpha.** Core runtime stable. 3,232 tests collected on Python 3.11 / 3.12. Eleven of twelve backend protocols shipped (see the backend protocols table above); `MCPServerRegistryBackend` in progress (PR 3 of 5). The surface stabilizes at v1.0. Pre-1.0 — Minor releases may contain breaking changes (see [`docs/deployment/versioning.md`](docs/deployment/versioning.md)). Single-maintainer project; reference implementation anyone can use, fork, or extend.
30 changes: 30 additions & 0 deletions atomic_agents/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ def cleanup_stale_tempfiles(directory: Path) -> list[Path]:
"""Find and delete leftover .tmp files from crashed writes.

Run as part of lint or startup. Returns the list of files cleaned.

Note: this uses rglob which scans the entire directory tree recursively.
Prefer cleanup_stale_tempfiles_for_file when the target file is known;
that function is scoped to siblings of a specific file rather than the
full tree.
"""
cleaned = []
if not directory.exists():
Expand All @@ -135,3 +140,28 @@ def cleanup_stale_tempfiles(directory: Path) -> list[Path]:
except FileNotFoundError:
pass
return cleaned


def cleanup_stale_tempfiles_for_file(target: Path) -> list[Path]:
"""Delete leftover .tmp files from crashed atomic_write calls for target.

Scoped to the parent directory of target, matching only tempfiles that
atomic_write would have created for this specific file. The pattern is
`.<name>.<random>.tmp` (the same pattern atomic_write uses when creating
the temporary file next to the destination).

Returns the list of files removed. Ignores FileNotFoundError races
(another process may have already cleaned the same file).

Use inside a lock so cleanup is serialized with the install/uninstall
operation that follows.
"""
cleaned = []
pattern = f".{target.name}.*.tmp"
for path in target.parent.glob(pattern):
try:
path.unlink()
cleaned.append(path)
except FileNotFoundError:
pass
return cleaned
Loading