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: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

## Checklist

- [ ] I read [`CONTRIBUTING.md`](../CONTRIBUTING.md) and (for subsystem work) the local `CLAUDE.md`.
- [ ] I read [`CONTRIBUTING.md`](../CONTRIBUTING.md) and (for subsystem work) the local `AGENTS.md`.
- [ ] `pre-commit run --all-files` passes.
- [ ] `pytest tests/` passes; I added/updated tests for new behavior.
- [ ] Bug fixes cite `file:line` in the description.
Expand Down
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version: 2
# All updates open against `dev` — the integration branch (see CLAUDE.md §6);
# All updates open against `dev` — the integration branch (see AGENTS.md §6);
# `main` only receives promotion PRs.
updates:
- package-ecosystem: "pip"
Expand Down
2 changes: 1 addition & 1 deletion .planning/PROJECT.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,6 @@ This document evolves at phase transitions and milestone boundaries.
This document and its siblings are *agent-maintained*. They succeed when:

- A fresh AI agent dropped into the repo can answer *"what is jvagent for?"* by reading this file alone.
- A fresh AI agent dropped into a subsystem (`jvagent/core/`, `jvagent/action/orchestrator/`, etc.) can do correct local work by reading the local `CLAUDE.md` alone.
- A fresh AI agent dropped into a subsystem (`jvagent/core/`, `jvagent/action/orchestrator/`, etc.) can do correct local work by reading the local `AGENTS.md` alone.
- Every claim about runtime behavior in [`SPEC.md`](SPEC.md) cites a file:line in the source.
- Every load-bearing design decision is captured in an [`adr/`](adr/).
2 changes: 1 addition & 1 deletion .planning/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# .planning — agent-facing design docs

Reference material for **AI agents and human contributors** working on jvagent.
The repo-root [`CLAUDE.md`](../CLAUDE.md) is the agent entry point; this folder
The repo-root [`AGENTS.md`](../AGENTS.md) is the agent entry point; this folder
holds the deeper normative specs, reference guides, runbooks, and decision
records it links into. User-facing onboarding lives in the root
[`README.md`](../README.md).
Expand Down
4 changes: 2 additions & 2 deletions .planning/adr/0033-identity-and-locking-substrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- **Status:** Accepted — implemented 2026-07-17 (identity index #86, boot dedupe #87, contextvar hygiene #91, per-session conversation lock #99, turn-lock lease renewal #100, distributed bootstrap lease #101). Remaining: cross-worker upsert-by-identity for User/Conversation (in-process races locked; cross-process now rides the lease infra — small follow-up).
- **Date:** 2026-07-16
- **Supersedes / amends:** contracts in `jvagent/core/CLAUDE.md` §3, `jvagent/memory/CLAUDE.md` §3/§7 (the "compound index rejects on save" claim), and the singleton-enforcement narrative in `jvagent/action/actions.py`.
- **Supersedes / amends:** contracts in `jvagent/core/AGENTS.md` §3, `jvagent/memory/AGENTS.md` §3/§7 (the "compound index rejects on save" claim), and the singleton-enforcement narrative in `jvagent/action/actions.py`.
- **Related:** review [`.planning/reviews/2026-07-16-core-review.md`](../reviews/2026-07-16-core-review.md); ADR-0003 (interaction pruning), ADR-0020 (public auth / session tokens).

## Context
Expand Down Expand Up @@ -54,7 +54,7 @@ Run a lightweight identity-reconcile (dedupe by identity tuple, using raw record

- **Positive:** the duplicate-singleton class (C1–C6) and the lost-update / double-claim class (C7–C9, H18) are closed at the substrate. Mongo deployments stop silently losing actions. The default `json` adapter gets a real single-writer guarantee via the bootstrap lease.
- **Costs:** raw-record queries are slightly more code than `find_one`; a distributed lease adds a dependency for multi-replica correctness (optional, with a documented single-writer fallback). Boot-time reconcile adds bounded startup work.
- **Contract changes:** update `core/CLAUDE.md` and `memory/CLAUDE.md` to state that uniqueness is enforced by the application layer (upsert-by-identity + lease), and remove the false "compound index rejects on save" claim for the default adapter.
- **Contract changes:** update `core/AGENTS.md` and `memory/AGENTS.md` to state that uniqueness is enforced by the application layer (upsert-by-identity + lease), and remove the false "compound index rejects on save" claim for the default adapter.
- **Test debt:** requires the currently-absent concurrency suite (duplicate create, lease expiry, contextvar reentrancy, double-claim) — treated as acceptance criteria, not follow-up.

## Alternatives considered
Expand Down
6 changes: 3 additions & 3 deletions .planning/archive/executive-build-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
> [`../docs/ORCHESTRATOR.md`](../../docs/ORCHESTRATOR.md). This file is retained only to
> preserve the original design intent, mirroring how ADR-0010 itself is kept.
>
> Paste this to Claude Code (or any coding agent) at the repo root of `jvagent`. It is self-contained but assumes the repo's `CLAUDE.md`, `.planning/SPEC.md`, and `.planning/adr/0010-executive-centers-architecture.md` are present.
> Paste this to Claude Code (or any coding agent) at the repo root of `jvagent`. It is self-contained but assumes the repo's `AGENTS.md`, `.planning/SPEC.md`, and `.planning/adr/0010-executive-centers-architecture.md` are present.

---

## Mission

Implement the **Executive + Centers** deployment pattern specified in `.planning/adr/0010-executive-centers-architecture.md`. It is a new, additive pattern that ships **alongside** the Rails pattern — no forced migration, no harness subsumption. ADR-0010 is the **source of truth**; if anything below conflicts with it, the ADR wins and you flag the conflict.

Read first, in order: `CLAUDE.md`, `.planning/adr/0010-executive-centers-architecture.md`, `.planning/SPEC.md` (§3.3–§3.4, §11).
Read first, in order: `AGENTS.md`, `.planning/adr/0010-executive-centers-architecture.md`, `.planning/SPEC.md` (§3.3–§3.4, §11).

## Mental model (so you make correct judgment calls)

Expand Down Expand Up @@ -63,7 +63,7 @@ A brain. One **Executive** (prefrontal cortex, light model) engages trivial conv

**M8 — Scaffolder profile + example.** `executive` profile in `jvagent/scaffold/builtin_profiles/`; `examples/jvagent_app/agents/jvagent/executive_agent/`. *Tests:* scaffold smoke; `jvagent ... validate` passes; a second orchestrator at `-200` rejected. *Exit:* `jvagent app create --profile executive` yields a working agent.

**M9 — Observability + docs + parity.** Activation-trace events on `Interaction`; `docs/ORCHESTRATOR.md`; `PATTERNS.md` + `GLOSSARY.md` + top-level `CLAUDE.md` updated; a smoke harness (`tests/action/executive/smoke_executive.py`) running the 6-utterance suite, archived under `baselines/`. *Exit:* a turn is fully traceable from one log query; smoke runs clean; pattern documented as a peer.
**M9 — Observability + docs + parity.** Activation-trace events on `Interaction`; `docs/ORCHESTRATOR.md`; `PATTERNS.md` + `GLOSSARY.md` + top-level `AGENTS.md` updated; a smoke harness (`tests/action/executive/smoke_executive.py`) running the 6-utterance suite, archived under `baselines/`. *Exit:* a turn is fully traceable from one log query; smoke runs clean; pattern documented as a peer.

## Testing & verification

Expand Down
2 changes: 1 addition & 1 deletion .planning/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@
},
"project_code": "jvagent",
"agent_skills": {},
"claude_md_path": "./CLAUDE.md"
"claude_md_path": "./AGENTS.md"
}
2 changes: 1 addition & 1 deletion .planning/plans/2026-08-03-skill-only-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

Why a new module rather than more lines in `orchestrator_interact_action.py`: that file is already 3388 lines, and the repo's established pattern is one concern per module (`access.py`, `egress.py`, `catalog.py`, `continuation.py`). The gate is a closed, testable unit with no orchestrator dependencies.

**Conventions for every task:** the commit gate in [CLAUDE.md](../../CLAUDE.md) §6 is mandatory — `pre-commit run --all-files` **and** the affected pytest slice must pass before each commit. Do not use `--no-verify`. Commits are authored as the repo user with no Claude co-author trailer.
**Conventions for every task:** the commit gate in [AGENTS.md](../../AGENTS.md) §6 is mandatory — `pre-commit run --all-files` **and** the affected pytest slice must pass before each commit. Do not use `--no-verify`. Commits are authored as the repo user with no Claude co-author trailer.

---

Expand Down
10 changes: 10 additions & 0 deletions .planning/reference/action-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,23 @@ async def on_register(self):

## 13. Common pitfalls

Actions inherit jvspatial's protected entity setter. Declare persisted state with `attribute(...)` and runtime-only underscore state with Pydantic `PrivateAttr` on the class. Do this for clients, registries, caches, and per-turn flags set after initialization. Declared private methods may be replaced on an instance in tests; undeclared `_name` assignments raise `AttributeError`. Keep test doubles on real IDs when exercising JsonDB, which now rejects malformed entity IDs.

```python
from pydantic import PrivateAttr

class MyAction(Action):
_registry: dict[str, object] = PrivateAttr(default_factory=dict)
```

| Mistake | Fix |
|---|---|
| Forgetting `from . import endpoints` in `__init__.py` | Endpoints don't register. Add the import. |
| Naming the class differently from `archetype` in `info.yaml` | Loader fails to find the class. Match exactly. |
| Top-level `InteractAction` not routing to children | Child actions never execute. Call `await visitor.visit(child)` from `execute()`. |
| Long sync work inside `execute()` | Blocks the response. Use `run_in_background=True` for non-critical work, or enqueue a `PROACTIVE` task via `TaskStore.enqueue_proactive` / `TaskMonitor`. |
| Mutating `self.metadata` directly | Lost on next load — `metadata` is rebuilt from `info.yaml`. Use `attribute(...)` fields for persistent state. |
| Assigning `self._registry` without declaring it | jvspatial rejects the undeclared name. Add a typed Pydantic `PrivateAttr` on the class. |
| Swallowing exceptions in lifecycle hooks | Errors go silent. Let them propagate — the framework's `enable()`/`disable()` wrappers log them. |
| Hard-coding API keys | Use `attribute(default="")` + agent.yaml `${ENV_VAR}` indirection. |
| Skipping `info.yaml` | Loader skips the action package. Always ship one. |
Expand Down
12 changes: 8 additions & 4 deletions .planning/reference/jvspatial-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
## 1. Where jvspatial lives

- **Source**: `/Users/eldonmarks/Briefcase/dev/jv/jvspatial` (sibling directory in this workspace).
- **Pip install**: declared in [`pyproject.toml`](../../pyproject.toml) as `jvspatial==0.0.21`.
- **Pip install**: [`pyproject.toml`](../../pyproject.toml) and both requirements files temporarily pin the exact patched jvspatial Git commit. Replace all three refs with the published patched version before publishing jvagent; a fresh `pip install -e '.[test]'` must resolve the reviewed commit in `jvspatial`'s `direct_url.json`.
- **Own docs**: jvspatial has its own [`README.md`](../../../jvspatial/README.md) and [`SPEC.md`](../../../jvspatial/SPEC.md). Treat those as authoritative for anything below.

---
Expand All @@ -20,8 +20,8 @@
Object ── persistence-capable Pydantic-style base
└── Node ── graph node, has edges + visitor support
├── Edge ── relationship between two Nodes
└── Walker ── traverses a graph, visits Nodes
└── Root ── singleton Node, anchor for everything
└── Root ── singleton Node, anchor for everything
Walker ── separate traversal class; visits Nodes
```

- `Object` (`jvspatial/core/entities/object.py:19`) — base persistence-capable class with id, entity type, graph context. All entity types inherit. Pydantic-aware.
Expand All @@ -30,6 +30,8 @@ Object ── persistence-capable Pydantic-style base
- `Walker` (`jvspatial/core/entities/walker.py:83`) — traversal agent. Visit queue + trail. Built-in protection: `max_steps=10000`, `max_visits_per_node=100`, `max_execution_time=300s`, `max_queue_size=1000`.
- `Root` (`jvspatial/core/entities/root.py:11`) — singleton; id fixed at `"n.Root.root"`. Created once.

`Object.__setattr__` rejects undeclared fields, including new underscore names. Use `attribute(...)` for persisted state and Pydantic `PrivateAttr` for action-local runtime state (for example a registry, client, or cached dispatch state). A private method already declared on the class can be replaced on an instance for a test double; this does not allow an arbitrary new `_helper`. Do not bypass the setter with `object.__setattr__`.

### 2.2 Walker API (read by every InteractAction author)

| Method | Signature | Purpose |
Expand Down Expand Up @@ -77,6 +79,8 @@ async def my_handler(...): ...
- `roles=[...]` restricts to those roles.
- Endpoints inside an action package's `endpoints.py` are auto-discovered at action register time.

With auth enabled, jvspatial caps register, login, forgot-password, and reset-password at five requests per 60 seconds per IP even when its global limiter is off. Test hosts or applications with an equivalent trusted limiter may explicitly set `RateLimitConfig(auth_entrypoint_rate_limit_enabled=False)`; do not assume the global limiter flag covers those routes. Authenticated mounted ASGI and raw FastAPI routes may lack jvspatial endpoint metadata and remain reachable after authentication; built-in `/status`, `/logs`, and `/graph` routes still require admin roles.

### 2.5 Persistence

jvspatial supports five backends usable from jvagent, selected via env vars:
Expand All @@ -100,7 +104,7 @@ await node.save() # Required after property mutatio
results = await MyNode.find({"context.x": 1}) # Mongo-style query
```

`Object.count()` does not exist — use `len(await Entity.find(query))` (jvspatial SPEC.md). For high-cardinality counts, design indexes accordingly.
`Object.count(query)` is available; use it instead of loading every matching entity just to count them.

### 2.6 Context

Expand Down
2 changes: 1 addition & 1 deletion .planning/reference/memory-and-pruning.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Memory & Pruning

> Deep dive on `User` / `Conversation` / `Interaction` lifecycle and the rolling-window pruning mechanism. Companion to [`SPEC.md`](../SPEC.md) §5, [`jvagent/memory/CLAUDE.md`](../../jvagent/memory/CLAUDE.md), [`adr/0003-interaction-limit-pruning.md`](../adr/0003-interaction-limit-pruning.md).
> Deep dive on `User` / `Conversation` / `Interaction` lifecycle and the rolling-window pruning mechanism. Companion to [`SPEC.md`](../SPEC.md) §5, [`jvagent/memory/AGENTS.md`](../../jvagent/memory/AGENTS.md), [`adr/0003-interaction-limit-pruning.md`](../adr/0003-interaction-limit-pruning.md).

---

Expand Down
2 changes: 1 addition & 1 deletion .planning/reference/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,4 @@ If you add one of these, document it here and in [`/docs/logging.md`](../../docs
- [`/docs/logging.md`](../../docs/logging.md) (734 lines) — comprehensive logging architecture
- [`/docs/error-logging.md`](../../docs/error-logging.md) (401 lines) — error rollup mechanics
- [`/docs/interaction-logging.md`](../../docs/interaction-logging.md) (275 lines) — turn-level events + INTERACTION level
- Local subsystem guide: [`/jvagent/logging/CLAUDE.md`](../../jvagent/logging/CLAUDE.md)
- Local subsystem guide: [`/jvagent/logging/AGENTS.md`](../../jvagent/logging/AGENTS.md)
4 changes: 2 additions & 2 deletions .planning/reviews/2026-07-16-core-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Lower-severity items (equal-timestamp chain infinite loop `interaction.py:741-75

### Phase 5 — Test debt (blocks regressions in all of the above)
- **Concurrency suite** (currently zero): duplicate User/Conversation/action creation; lock-lease expiry mid-turn; contextvar reentrancy; proactive double-claim; concurrent turns on one conversation.
- **Pruning regression suite**: the two test files `memory/CLAUDE.md` references **do not exist**; `_prune_old_interactions` (cap, chain rewiring, `last_interaction_id`, limit-sync) is essentially untested.
- **Pruning regression suite**: the two test files `memory/AGENTS.md` references **do not exist**; `_prune_old_interactions` (cap, chain rewiring, `last_interaction_id`, limit-sync) is essentially untested.
- **Interact auth**: `log`-mode no-leak, streaming-path identity guard parity, rate-limiter spoofing/isolation.
- **Repair multi-tick resume**, **loop-lifecycle** (scheduler actually fires after `run_server`), **reply endpoint authz**, **`get_model_action` fallback**, deregistration cleanup paths.

Expand All @@ -160,6 +160,6 @@ Lower-severity items (equal-timestamp chain infinite loop `interaction.py:741-75
## 3. Suggested sequencing for review

- **Ship now as isolated security patches:** Phase 0 items 1–4 (rate limiter, reply authz, reason leak, log-mode token). Each is small and independently testable.
- **One design ADR** for Phase 1+2 (identity + locking substrate) — it changes contracts in `core/CLAUDE.md` and `memory/CLAUDE.md` and supersedes the "compound index rejects on save" claim, which is false on the default adapter.
- **One design ADR** for Phase 1+2 (identity + locking substrate) — it changes contracts in `core/AGENTS.md` and `memory/AGENTS.md` and supersedes the "compound index rejects on save" claim, which is false on the default adapter.
- **Phase 3/4** as per-subsystem PRs behind the substrate work.
- Treat **Phase 5** as acceptance criteria, not a follow-up: the high-severity band is entirely untested today.
6 changes: 3 additions & 3 deletions .planning/reviews/2026-09-01-full-code-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The codebase is well-engineered where invariants are mechanically checkable (asy
| **pytest** (`pytest tests/ -p no:randomly`) | **PASS** (exit 0) | 3,558 tests collected |
| **mypy dev venv** (`mypy jvagent/`) | **FAIL** | **270 errors in 48 files** (local mypy 1.20.1 with jvspatial installed) |

**Mypy gap:** CLAUDE.md asserts the pre-commit hook and bare `mypy jvagent/` are aligned; they are not. Inside the isolated pre-commit env every jvspatial type is `Any`, so boundary errors like `"Object" has no attribute "name"` (`cli/agent_commands.py:248`) and `AuthConfig` keyword mismatches (`cli/server_config.py:418`) are invisible to the enforced gate. Representative errors live precisely at the jvagent↔jvspatial boundary — the area most likely to hide real runtime bugs.
**Mypy gap:** AGENTS.md asserts the pre-commit hook and bare `mypy jvagent/` are aligned; they are not. Inside the isolated pre-commit env every jvspatial type is `Any`, so boundary errors like `"Object" has no attribute "name"` (`cli/agent_commands.py:248`) and `AuthConfig` keyword mismatches (`cli/server_config.py:418`) are invisible to the enforced gate. Representative errors live precisely at the jvagent↔jvspatial boundary — the area most likely to hide real runtime bugs.

---

Expand Down Expand Up @@ -280,7 +280,7 @@ Memory user-listing returns HTTP 200 with `total=0` on backend outage; `_send_to

Pre-commit passes; dev venv reports 270 errors. Hook lacks jvspatial/pydantic/httpx stubs, so boundary types are unchecked — precisely where integration bugs live.

**Fix theme:** Add jvspatial (and key deps) to hook `additional_dependencies`, or pin a shared stub package; align CLAUDE.md claim with reality.
**Fix theme:** Add jvspatial (and key deps) to hook `additional_dependencies`, or pin a shared stub package; align AGENTS.md claim with reality.

---

Expand Down Expand Up @@ -387,7 +387,7 @@ Most HIGH and MEDIUM items from the 2026-09-01 review are now addressed. Remaini

- Prior core review: [2026-07-16-core-review.md](2026-07-16-core-review.md) (H19 = C3)
- Prior once-over: [2026-07-17-once-over.md](2026-07-17-once-over.md)
- Agent guide: [CLAUDE.md](../../CLAUDE.md)
- Agent guide: [AGENTS.md](../../AGENTS.md)
- Orchestrator design: [docs/ORCHESTRATOR.md](../../docs/ORCHESTRATOR.md)
- Thin harness: [docs/thin-harness.md](../../docs/thin-harness.md)

Expand Down
Loading
Loading