diff --git a/.claude/rules/architecture.md b/.claude/rules/architecture.md index d1484eb..7c2a645 100644 --- a/.claude/rules/architecture.md +++ b/.claude/rules/architecture.md @@ -1,58 +1,8 @@ ## Architecture -llm-connect is structured as a **GAAF-2026 layered library**. See -`ARCHITECTURE-LAYERS.md` for the full layer map and scorecard. + -### Layer summary +## Quick Reference -``` -Core (frozen after v1) - LLMAdapter ABC adapter.py - RunConfig / LLMResponse models.py - LLMError hierarchy exceptions.py - MockLLMAdapter adapter.py ← test primitive, belongs with Core - -Functional (evolvable, independently shippable) - OpenAIAdapter openai.py - GeminiAdapter gemini.py - OpenRouterAdapter openrouter.py - ClaudeCodeAdapter claude_code.py - EmbeddingAdapter ABC embedding_adapter.py - OpenAICompatibleEmbeddingAdapter embedding_openai.py - EmbeddingCache embedding_cache.py - create_adapter() factory.py - create_embedding_adapter() embedding_factory.py - _token_estimator _token_estimator.py - similarity utilities similarity.py - -Configuration (user-controlled declarative state) - resolve_llm() chain toml_config.py ← 7-level TOML priority chain - LLMConfig / load_config config.py - _http shared utility _http.py ← also used by Functional adapters -``` - -### Dependency rule - -Core ← Functional ← Configuration -No upward dependencies. `_http.py` is consumed by Functional only. - -### Key design decisions - -**API key resolution** (`config.resolve_api_key`): three-step chain — -explicit argument → environment variable → plaintext key file in project root. -Adapters raise `LLMConfigurationError` at construction time if no key is found -(except `ClaudeCodeAdapter` which needs no key). - -**TOML config chain** (`toml_config.resolve_llm`): 7 priority levels allow -per-project and per-user LLM preferences. Currently defaults to `markitect` -app_name for backward compatibility — consumers pass their own `app_name`. - -**Factory pattern** (`factory.create_adapter`): lazy imports prevent pulling -all provider SDKs at module load. Add a new provider by registering its FQN -in `_PROVIDERS`. - -**ClaudeCodeAdapter subprocess model**: prompt is piped via stdin (not CLI -arg) to avoid shell argument length limits on large prompts (>30 KB). - -**Retry logic**: `OpenAIAdapter` and `OpenRouterAdapter` retry on 429 and 5xx -with exponential backoff. `GeminiAdapter` does not (rate-limit handling deferred). +`~/state-hub/mcp_server/TOOLS.md` — MCP tool reference diff --git a/.claude/rules/repo-boundary.md b/.claude/rules/repo-boundary.md index 8588075..12526d9 100644 --- a/.claude/rules/repo-boundary.md +++ b/.claude/rules/repo-boundary.md @@ -1,17 +1,8 @@ ## Repo boundary -This repo owns **llm-connect** — the multi-provider LLM client library — only. +This repo owns **llm-connect** only. It does not own: -It does NOT own: - -- **API key storage / secret management** → caller's environment (env vars, - key files, vault). llm-connect resolves keys but does not store them. -- **Consumer routing logic** → `inter-hub/AgentBridge.hs`, `markitect` etc. - `RoutingPolicy` (WP-0003) provides primitives; policy data belongs in the consumer. -- **The Claude Code CLI binary** → installed separately; `ClaudeCodeAdapter` - shells out to it. -- **markitect application code** → `markitect.llm` is a shim that re-exports - from here; all implementation lives in this repo. -- **State hub / custodian infrastructure** → `the-custodian/state-hub/` -- **IHF bridge scripts** → `inter-hub/scripts/llm_bridge.py` lives in inter-hub, - not here. llm-connect is a dependency of that script. + diff --git a/.claude/rules/session-protocol.md b/.claude/rules/session-protocol.md index 0394618..59afff5 100644 --- a/.claude/rules/session-protocol.md +++ b/.claude/rules/session-protocol.md @@ -1,6 +1,6 @@ ## Session Protocol -State Hub: http://127.0.0.1:8000 (local) · http://127.0.0.1:18000 (CoulombCore via ops-bridge) +State Hub: http://127.0.0.1:8000 **Step 1 — Orient** @@ -8,24 +8,38 @@ Read the offline-safe brief first — it works without a live hub connection: ```bash cat .custodian-brief.md ``` -Then call the MCP tool for richer cross-domain context (skip if unreachable): +Then call the MCP tool for richer cross-domain context when MCP tools are exposed: ``` get_domain_summary("custodian") ``` -If the hub is offline: `cd ~/the-custodian/state-hub && make api` +If MCP tools are unavailable in the current agent session, use the REST API: +```bash +curl -s "http://127.0.0.1:8000/state/summary" | python3 -m json.tool +``` +If the hub is offline: `cd ~/state-hub && make api` **Step 2 — Check inbox** +With MCP tools: ``` get_messages(to_agent="llm-connect", unread_only=True) ``` Mark read with `mark_message_read(message_id)`. Reply or act on coordination requests before proceeding. +Without MCP tools: +```bash +curl -s "http://127.0.0.1:8000/messages/?to_agent=llm-connect&unread_only=true" \ + | python3 -m json.tool +curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ + -H "Content-Type: application/json" -d '{}' +``` + **Step 3 — Scan workplans** ```bash ls workplans/ ``` -For each file with `status: active`, note pending `todo`/`in_progress` tasks. +For each file with `status: ready`, `active`, or `blocked`, note pending +`todo`/`in_progress` tasks. **Step 4 — Present brief** @@ -45,18 +59,25 @@ If no workstreams: follow First Session Protocol (`first-session.md`). > are First Session Protocol only. Work structure belongs in repo files (ADR-001). **Session close:** +With MCP tools: ``` add_progress_event(summary="...", topic_id="cee7bedf-2b48-46ef-8601-006474f2ad7a", workstream_id="") ``` +Without MCP tools: +```bash +curl -s -X POST http://127.0.0.1:8000/progress/ \ + -H "Content-Type: application/json" \ + -d '{"topic_id":"cee7bedf-2b48-46ef-8601-006474f2ad7a","workstream_id":"","event_type":"note","summary":"what changed","author":"codex"}' +``` If workplan files were modified, ensure the local copy is up to date first: ```bash git -C pull --ff-only -cd ~/the-custodian/state-hub && make fix-consistency REPO=llm-connect +cd ~/state-hub && make fix-consistency REPO=llm-connect ``` For repos where implementation runs on a remote machine (e.g. CoulombCore), use the combined target which pulls before fixing: ```bash -cd ~/the-custodian/state-hub && make fix-consistency-remote REPO=llm-connect +cd ~/state-hub && make fix-consistency-remote REPO=llm-connect ``` **C-15** (DB task ahead of file) is normal in multi-machine workflows — writeback will sync the file to match DB. **C-16** (repo behind remote) blocks all writes diff --git a/.claude/rules/stack-and-commands.md b/.claude/rules/stack-and-commands.md index f1d0216..dc53ac6 100644 --- a/.claude/rules/stack-and-commands.md +++ b/.claude/rules/stack-and-commands.md @@ -1,59 +1,19 @@ ## Stack -- **Language:** Python 3.10+ -- **Key deps (runtime):** `toml` (TOML config parsing) -- **Key deps (dev):** `pytest`, `ruff`, `mypy` -- **HTTP:** stdlib `urllib` via `_http.py` (no requests/httpx runtime dep) -- **Build:** setuptools / uv + +- **Language:** +- **Key deps:** ## Dev Commands ```bash -# Install (editable, with dev extras) -uv pip install -e ".[dev]" -# or -pip install -e ".[dev]" +# TODO: Fill in the standard commands for this repo + +# Install dependencies # Run tests -uv run pytest -# or -pytest -# Lint -uv run ruff check . +# Lint / type check -# Type check -uv run mypy llm_connect - -# Run a single test file -uv run pytest tests/test_models.py -v - -# Build package (dry run) -uv build --no-sources -``` - -## Project layout - -``` -llm_connect/ source package - adapter.py LLMAdapter ABC + Mock/ErrorLLMAdapter - models.py RunConfig, LLMResponse - exceptions.py LLMError hierarchy - factory.py create_adapter() - openai.py OpenAIAdapter - gemini.py GeminiAdapter - openrouter.py OpenRouterAdapter - claude_code.py ClaudeCodeAdapter - embedding_adapter.py EmbeddingAdapter ABC - embedding_openai.py OpenAICompatibleEmbeddingAdapter - embedding_cache.py EmbeddingCache - embedding_factory.py create_embedding_adapter() - toml_config.py 7-level TOML config resolution - config.py LLMConfig, resolve_api_key, find_project_root - _http.py shared HTTP POST utility - _token_estimator.py rough token count estimate - similarity.py cosine similarity utilities -tests/ pytest test suite -contracts/ GAAF-2026 contract docs -workplans/ workplan files (LLM-WP-NNNN) +# Build / package (if applicable) ``` diff --git a/.claude/rules/workplan-convention.md b/.claude/rules/workplan-convention.md index 5618a44..8ad0f27 100644 --- a/.claude/rules/workplan-convention.md +++ b/.claude/rules/workplan-convention.md @@ -5,6 +5,22 @@ ID prefix: `LLM-WP` Work items originate as files in this repo **before** being registered in the hub. +Canonical workplan/workstream frontmatter statuses are: +`proposed`, `ready`, `active`, `blocked`, `backlog`, `finished`, `archived`. +Use `proposed` for a newly drafted plan, `ready` after review against current +repo state, and `finished` when implementation is complete. `stalled` and +`needs_review` are derived health labels, not stored statuses. + +Closed workplans may be moved to `workplans/archived/` with a completion-date +prefix: `YYMMDD-llm-connect-WP-NNNN-.md`. The frontmatter id remains +unchanged; the prefix is only for quick visual reference. + +Small opportunistic tasks discovered during another session use **Ad Hoc Tasks**: +`workplans/ADHOC-YYYY-MM-DD.md`, workstream slug `adhoc-YYYY-MM-DD`, and task ids +`ADHOC-YYYY-MM-DD-T01`, `T02`, etc. Use adhocs only for low-risk work completed +directly. Promote anything requiring analysis, design, approval, dependencies, or +multiple planned phases into a normal workplan. + Ecosystem todos from other agents arrive as `[repo:llm-connect]` hub tasks — visible at session start. Pick one up by creating the workplan file, then registering the workstream. diff --git a/AGENTS.md b/AGENTS.md index db45910..39bac20 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,11 +1,162 @@ -# llm-connect — Codex Instructions +# llm-connect — Agent Instructions -@SCOPE.md -@.claude/rules/repo-identity.md -@.claude/rules/session-protocol.md -@.claude/rules/first-session.md -@.claude/rules/workplan-convention.md -@.claude/rules/stack-and-commands.md -@.claude/rules/architecture.md -@.claude/rules/repo-boundary.md -@.claude/rules/agents.md +## Repo Identity + +**Purpose:** Multi-provider LLM client library — unified adapter interface for OpenAI, Claude, Gemini, OpenRouter with embedding support, token estimation, and TOML-based config. + +**Domain:** custodian +**Repo slug:** llm-connect +**Topic ID:** `cee7bedf-2b48-46ef-8601-006474f2ad7a` +**Workplan prefix:** `LLM-WP-` + +--- + +## State Hub Integration + +The Custodian State Hub tracks work across all domains. Interact via HTTP REST — +there is no MCP server for Codex agents. + +| Context | URL | +|---------|-----| +| Local workstation | `http://127.0.0.1:8000` | +| Remote via tunnel | `http://127.0.0.1:18000` | + +### Orient at session start + +```bash +# Offline brief — works without hub connection +cat .custodian-brief.md + +# Active workstreams for this domain +curl -s "http://127.0.0.1:8000/workstreams/?topic_id=cee7bedf-2b48-46ef-8601-006474f2ad7a&status=active" \ + | python3 -m json.tool + +# Check inbox +curl -s "http://127.0.0.1:8000/messages/?to_agent=llm-connect&unread_only=true" \ + | python3 -m json.tool +``` + +Mark a message read: +```bash +curl -s -X PATCH "http://127.0.0.1:8000/messages//read" \ + -H "Content-Type: application/json" -d '{}' +``` + +### Log progress (required at session close) + +```bash +curl -s -X POST http://127.0.0.1:8000/progress/ \ + -H "Content-Type: application/json" \ + -d '{ + "summary": "what was done", + "event_type": "note", + "author": "codex", + "workstream_id": "", + "task_id": "" + }' +``` + +Omit `workstream_id` / `task_id` when not applicable. + +### Update task status + +```bash +curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ + -H "Content-Type: application/json" \ + -d '{"status": "in_progress"}' +# values: todo | in_progress | done | blocked +``` + +### Flag a task for human review + +```bash +curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ + -H "Content-Type: application/json" \ + -d '{"needs_human": true, "intervention_note": "reason"}' +``` + +--- + +## Session Protocol + +**Start:** +1. `cat .custodian-brief.md` — domain goal and open workstreams (offline-safe) +2. Check inbox: `GET /messages/?to_agent=llm-connect&unread_only=true`; mark read +3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks +4. Check blocked tasks: `GET /tasks/?needs_human=true` + +**During work:** +- Update task statuses in workplan files as tasks progress +- Record significant decisions via `POST /decisions/` + +**Close:** +1. Update workplan file task statuses to reflect progress +2. Log: `POST /progress/` with a summary of what changed +3. Note for the custodian operator: after workplan file changes, run from + `~/state-hub`: + ```bash + make fix-consistency REPO=llm-connect + ``` + This syncs task status from files into the hub DB. + +--- + +## Workplan Convention (ADR-001) + +Work items originate as files in this repo — not in the hub. The hub is a +read/cache/index layer that rebuilds from files. + +**File location:** `workplans/LLM-WP-NNNN-.md` + +**Archived location:** finished workplans may move to +`workplans/archived/YYMMDD-LLM-WP-NNNN-.md`. The `YYMMDD` prefix is +the completion/archive date; the frontmatter `id` does not change. + +**Ad Hoc Tasks:** small opportunistic fixes discovered during a session use +`workplans/ADHOC-YYYY-MM-DD.md` with task ids `ADHOC-YYYY-MM-DD-T01`, etc. Use +this only for low-risk work completed directly; create a normal workplan for +anything needing analysis, design, approval, dependencies, or multiple phases. + +**Frontmatter:** + +```yaml +--- +id: LLM-WP-NNNN +type: workplan +title: "..." +domain: custodian +repo: llm-connect +status: proposed | ready | active | blocked | backlog | finished | archived +owner: codex +topic_slug: ... +created: "YYYY-MM-DD" +updated: "YYYY-MM-DD" +state_hub_workstream_id: "" # written by fix-consistency — do not edit +--- +``` + +Use `proposed` for a new draft, `ready` after review against current repo +state, and `finished` after implementation. `stalled` and `needs_review` are +derived health labels, not frontmatter statuses. + +**Task block format** (one per `##` section): + +``` +## Task Title + +` ` `task +id: LLM-WP-NNNN-T01 +status: todo | in_progress | done | blocked +priority: high | medium | low +state_hub_task_id: "" # written by fix-consistency — do not edit +` ` ` + +Task description text. +``` + +Status progression: `todo` → `in_progress` → `done` (or `blocked`) + +To create a new workplan: +1. Write the file following the format above +2. Notify the custodian operator to run `make fix-consistency REPO=llm-connect` + (or send a message to the hub agent via `POST /messages/`)