diff --git a/.aider.conf.yml b/.aider.conf.yml deleted file mode 100644 index a16f762..0000000 --- a/.aider.conf.yml +++ /dev/null @@ -1,2 +0,0 @@ -read: .aider.conventions.md -auto-commits: false diff --git a/.aider.conventions.md b/.aider.conventions.md deleted file mode 100644 index 42ccd32..0000000 --- a/.aider.conventions.md +++ /dev/null @@ -1,255 +0,0 @@ -# Agent context — Mathias workspace - - - -## Who I am - -I'm Mathias, a digital product manager and technology consultant based in Sweden. -I build software, research emerging tech, and deliver consulting engagements -for clients under NDA. I work across AI/ML, financial automation, web applications, -and climate/sustainability tech. - -## How I work with agents - -- I think like a product manager — I care about *why* before *how* -- I want agents to be opinionated and push back, not just execute blindly -- I prefer concise responses; skip ceremony and get to the point -- When I say "build this", I mean production-quality with tests, not a demo -- Ask me before making irreversible changes or adding heavy dependencies -- I work with confidential client data — never send it to cloud APIs unless I explicitly say it's OK - -## Behavior rules - -These rules apply to every task across every project, regardless of harness. - -1. **No assumptions.** Don't hide confusion — surface it. Surface tradeoffs explicitly. - Think before coding; if the problem is unclear, ask or state assumptions before acting. -2. **Minimum viable code.** Solve with the smallest change that works. Nothing - speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first. -3. **Surgical changes.** Touch only what the task requires. Leave unrelated code, - files, and formatting alone. Diffs should be small and reviewable. -4. **Goal-driven execution.** Define clear success criteria up front for every task. - Loop — implement, verify, refine — until those criteria are met. Don't claim - completion without evidence (tests pass, command output, observed behavior). -5. **Trunk-Based Development — commit directly to main.** Every commit is one - logical change (one tool, one fix, one test) with passing tests. Main is always - deployable. Never create long-lived feature branches. - - **Exception — parallel agents on same repo:** If another agent is known to be - actively working on the same repo simultaneously, create a short-lived branch - (`agent/`), finish the task, and merge to main within the same - session. Do not leave agent branches open between sessions. - - **Exception — external contributor or client four-eyes requirement:** Use - PR flow only when a human reviewer outside the project is required. Document - the reason in PROJECT.md. - -## Default stack - -| Layer | Default | Fallback | Last resort | -|-------|---------|----------|-------------| -| Language | Go | Python | TypeScript, Java, C | -| UI | HTMX + Templ | Server-rendered HTML | React (only if SPA is justified) | -| Build | Task (taskfile.dev) | Make | — | -| Containers | Docker Compose (dev), k3s (prod) | — | — | -| DB | PostgreSQL + sqlc | SQLite | — | -| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — | -| Logging | slog (structured) | — | — | -| Testing | Table-driven, testify | — | — | -| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — | - -Exploratory: Rust, Zig — I'll tell you when I want these. - -## Code conventions - -- **Go style**: golines, gofumpt, golangci-lint -- **Errors**: `fmt.Errorf("operation: %w", err)` — never naked, never log-and-return -- **Naming**: stdlib conventions, no stuttering -- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs -- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), commit directly to main, - one logical change per commit, CI is the quality gate -- **Never**: long-lived feature branches, PRs for solo work, direct push without - passing `task check` locally first -- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config -- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message - -## Infrastructure - -Three machines on Tailscale: - -| Machine | Role | Key specs | -|---------|------|-----------| -| koala | GPU inference, heavy compute | RTX 5070, runs k3s + llama-swap + shared postgres18/pgvector | -| iguana | Services, builds | M2 Ultra Mac | -| flamingo | Daily driver, edge | Mac mini, ~/dev is here | - -- **Model routing**: LiteLLM in front of llama-swap (local) + cloud APIs (when permitted) -- **Orchestration**: k3s cluster across all three machines -- **Networking**: Tailscale mesh - -## Project landscape - -All development repos live at `~/dev/` (softlink from `~/Documents/local-dev/`). - -Organized in thematic folders: - -| Folder | Focus | Count | -|--------|-------|-------| -| `GO/` | Go web frameworks, API integrations, learning projects | ~10 | -| `AI/` | ML research, AI frameworks (FinRL, DSPy, crawl4ai) | ~6 | -| `AGENTS/` | Autonomous agents, coding agents, MCP servers, infra | ~15 | -| `QKX/` | Invoice processing, financial automation, payment systems | ~13 | -| `XT/` | Climate data, sustainability (Klimatkollen, Garbo) | ~2 | - -See `~/dev/PROJECT_SUMMARY.md` for detailed descriptions of each project. - -### Key active projects - -- **super-koala** (`AGENTS/`) — multi-component agent stack with LangGraph, DSPy, MCP -- **azure-tiger** (`QKX/`) — invoice extraction → ISO 20022 payment instructions -- **gocrwl** (`AGENTS/`) — Go web crawler with containerized deployment -- **koala-ai-stack** (`AGENTS/`) — local AI server infrastructure management -- **klimatkollen** (`XT/`) — Swedish municipal climate data platform - -## Knowledge base — actively use it - -A persistent brain (BM25 search + LLM-synthesised Q&A) survives across sessions, -hosts, and harnesses. It holds 100+ hard-won entries: infra incident postmortems, -Go pitfalls, framework gotchas, design principles, ADRs. **It is not optional -reference material — query it actively, not just when explicitly told.** - -### When to query (treat as a reflex) - -- **Before** starting a non-trivial task — search for prior art with the symptom - AND the system component ("how did we solve X in Y?"). 5 seconds beats 5 hours. -- **When debugging** — search for the error string, the stack frame, the affected - service. Past you may have already paid this tax. -- **Before adopting** a pattern, library, framework, or model name — check if it - was tried and rejected, or what the integration footguns are. -- **When making architectural decisions** — search for the domain + "ADR" or - "decision" to find prior reasoning before re-deriving it. -- **When a recommendation feels novel** — challenge yourself: "has this been - documented?" The brain often has it. - -### When to write - -After you discover something that **future-you would forget** and that **isn't -recoverable from the code, git log, or PR description alone**: - -- Bugs whose root cause is non-obvious and generalisable beyond this project. -- Framework / library / model-name quirks that bit you and would bite anyone. -- Design principles validated under fire (e.g. "every `_get` needs a `_list`"). -- Postmortems for incidents: what broke, why, how diagnosed, what to do next time. - -DON'T write project status, sprint progress, PR summaries, or "what I did this -session" — those rot fast and the originals are in git/gitea anyway. Brain -entries that age well are about *why*, *how to avoid*, and *what to do when*. - -### How to access (per harness) - -| Harness | Query | Write | -|---------|-------|-------| -| **Claude Code, Claude Desktop** | `brain_query` (BM25), `brain_answer` (LLM-synth + sources) MCP tools | `brain_write` MCP tool | -| **Crush, Pi, Antigravity, other MCP-capable** | same MCP server: `ingestion-brain` (via the `mcp__*_brain__*` namespace once authenticated) | same | -| **Anything HTTP-only (curl, scripts)** | `POST https://brain-mcp.d-ma.be/query` with `{"query":"..."}` (auth via `BRAIN_MCP_TOKEN`) | `POST .../write` with `{"content":"...","filename":"..."}` | -| **Browser / human inspection** | `https://gitea.d-ma.be/mathias/hyperguild` → `knowledge/` and `wiki/` markdown files | - -- **Scoping**: defaults to `public` collection; client projects filter to `{client}` + `public`. -- **Routing**: brain_answer's LLM uses berget.ai as primary, iguana ollama as - fallback. Both are configurable in the `supervisor/ingestion-deployment.yaml` - on the koala k3s cluster; don't hardcode local-only model names into the - berget URL (see knowledge entry on namespace mismatches). - -### Quick reflex checks - -If you find yourself about to say any of these out loud, you owe yourself a brain query first: - -- "I think the issue might be..." -- "Let me try X and see..." -- "I'll just write a script to..." -- "This is probably a new bug..." -- "Has anyone done this before?" — *yes, probably, go check.* - -## Client work rules - -When working on a project tagged with a client name: -1. Never send code, data, or context to cloud APIs — use local models only -2. Never reference other client projects or their data -3. Keep all artifacts within the client's git org / directory -4. Treat everything as confidential unless told otherwise - -## Harness-agnostic principles - -This context is designed to work with any AI coding tool: -- Claude Code, Cursor, Aider, Open WebUI, Charmbracelet Mods/Crush -- Pi Coding Agent, Mistral Vibe, Antigravity -- Any tool that accepts a system prompt or reads a markdown context file - -The canonical source is always `.context/AGENT.md` (root) and `.context/PROJECT.md` (per-project). -Derived files are committed (see *How context propagates* below) so a `git pull` on any host yields full agent context with no setup. - -## How context propagates - -Canonical sources of truth: -- Universal: `~/dev/.context/AGENT.md` (this file) -- Project: `/.context/PROJECT.md` (per-repo) - -Derived files (committed, regenerated by `task context:sync`): -- `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `.aider.conventions.md`, - `.context/system-prompt.txt` - -Workflow: -1. Edit a canonical file. Run `task context:sync`. Commit canonical and - derived together. Push. -2. On any other host, `git pull` brings both. Claude Code (tree-walking) - uses `CLAUDE.md`; Crush / Pi / Antigravity (cwd-only) use `AGENTS.md`; - Cursor uses `.cursorrules`; Aider uses `.aider.conventions.md`. -3. `task check` runs `context:sync` then asserts `git status --porcelain` - is empty over the derived files (catches both modified-tracked drift - and missing-untracked adapters). A drift fails the check with a - message telling you to stage the regenerated files. - -Behavior rules in this file and per-project rules in `PROJECT.md` apply -unconditionally on every host, every harness. - -## Engineering Skills - -Shared engineering skills are available in `~/dev/.skills/`. Load on demand via the index. - -See `~/dev/.skills/SKILLS_INDEX.md` for the full list with descriptions and "use when" triggers. - -Key skills: -- **TDD**: always write tests first — load `tdd` skill -- **Code Review**: load `code-review` skill before any review -- **SOLID/Clean Code**: load `solid` or `clean-code` skill for design work -- **Problem first**: load `problem-analysis` skill before coding non-trivial features - ---- - -# __PROJECT_NAME__ - -## Identity - -- **Name**: __PROJECT_NAME__ -- **Owner**: Mathias -- **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ -- **Status**: active - -## Stack - -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. - -## Agent - -TODO: describe what this agent does, what tools it has, and what it's responsible for. - -## Observability - -Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. -Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. diff --git a/.context/PROJECT.md b/.context/PROJECT.md deleted file mode 100644 index b69a2a8..0000000 --- a/.context/PROJECT.md +++ /dev/null @@ -1,22 +0,0 @@ -# __PROJECT_NAME__ - -## Identity - -- **Name**: __PROJECT_NAME__ -- **Owner**: Mathias -- **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ -- **Status**: active - -## Stack - -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. - -## Agent - -TODO: describe what this agent does, what tools it has, and what it's responsible for. - -## Observability - -Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. -Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. diff --git a/.context/system-prompt.txt b/.context/system-prompt.txt deleted file mode 100644 index 5dff007..0000000 --- a/.context/system-prompt.txt +++ /dev/null @@ -1,262 +0,0 @@ -You are a coding assistant working on a specific project. -Follow all conventions from both the root agent context and project context. - ---- - -# Agent context — Mathias workspace - - - -## Who I am - -I'm Mathias, a digital product manager and technology consultant based in Sweden. -I build software, research emerging tech, and deliver consulting engagements -for clients under NDA. I work across AI/ML, financial automation, web applications, -and climate/sustainability tech. - -## How I work with agents - -- I think like a product manager — I care about *why* before *how* -- I want agents to be opinionated and push back, not just execute blindly -- I prefer concise responses; skip ceremony and get to the point -- When I say "build this", I mean production-quality with tests, not a demo -- Ask me before making irreversible changes or adding heavy dependencies -- I work with confidential client data — never send it to cloud APIs unless I explicitly say it's OK - -## Behavior rules - -These rules apply to every task across every project, regardless of harness. - -1. **No assumptions.** Don't hide confusion — surface it. Surface tradeoffs explicitly. - Think before coding; if the problem is unclear, ask or state assumptions before acting. -2. **Minimum viable code.** Solve with the smallest change that works. Nothing - speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first. -3. **Surgical changes.** Touch only what the task requires. Leave unrelated code, - files, and formatting alone. Diffs should be small and reviewable. -4. **Goal-driven execution.** Define clear success criteria up front for every task. - Loop — implement, verify, refine — until those criteria are met. Don't claim - completion without evidence (tests pass, command output, observed behavior). -5. **Trunk-Based Development — commit directly to main.** Every commit is one - logical change (one tool, one fix, one test) with passing tests. Main is always - deployable. Never create long-lived feature branches. - - **Exception — parallel agents on same repo:** If another agent is known to be - actively working on the same repo simultaneously, create a short-lived branch - (`agent/`), finish the task, and merge to main within the same - session. Do not leave agent branches open between sessions. - - **Exception — external contributor or client four-eyes requirement:** Use - PR flow only when a human reviewer outside the project is required. Document - the reason in PROJECT.md. - -## Default stack - -| Layer | Default | Fallback | Last resort | -|-------|---------|----------|-------------| -| Language | Go | Python | TypeScript, Java, C | -| UI | HTMX + Templ | Server-rendered HTML | React (only if SPA is justified) | -| Build | Task (taskfile.dev) | Make | — | -| Containers | Docker Compose (dev), k3s (prod) | — | — | -| DB | PostgreSQL + sqlc | SQLite | — | -| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — | -| Logging | slog (structured) | — | — | -| Testing | Table-driven, testify | — | — | -| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — | - -Exploratory: Rust, Zig — I'll tell you when I want these. - -## Code conventions - -- **Go style**: golines, gofumpt, golangci-lint -- **Errors**: `fmt.Errorf("operation: %w", err)` — never naked, never log-and-return -- **Naming**: stdlib conventions, no stuttering -- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs -- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), commit directly to main, - one logical change per commit, CI is the quality gate -- **Never**: long-lived feature branches, PRs for solo work, direct push without - passing `task check` locally first -- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config -- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message - -## Infrastructure - -Three machines on Tailscale: - -| Machine | Role | Key specs | -|---------|------|-----------| -| koala | GPU inference, heavy compute | RTX 5070, runs k3s + llama-swap + shared postgres18/pgvector | -| iguana | Services, builds | M2 Ultra Mac | -| flamingo | Daily driver, edge | Mac mini, ~/dev is here | - -- **Model routing**: LiteLLM in front of llama-swap (local) + cloud APIs (when permitted) -- **Orchestration**: k3s cluster across all three machines -- **Networking**: Tailscale mesh - -## Project landscape - -All development repos live at `~/dev/` (softlink from `~/Documents/local-dev/`). - -Organized in thematic folders: - -| Folder | Focus | Count | -|--------|-------|-------| -| `GO/` | Go web frameworks, API integrations, learning projects | ~10 | -| `AI/` | ML research, AI frameworks (FinRL, DSPy, crawl4ai) | ~6 | -| `AGENTS/` | Autonomous agents, coding agents, MCP servers, infra | ~15 | -| `QKX/` | Invoice processing, financial automation, payment systems | ~13 | -| `XT/` | Climate data, sustainability (Klimatkollen, Garbo) | ~2 | - -See `~/dev/PROJECT_SUMMARY.md` for detailed descriptions of each project. - -### Key active projects - -- **super-koala** (`AGENTS/`) — multi-component agent stack with LangGraph, DSPy, MCP -- **azure-tiger** (`QKX/`) — invoice extraction → ISO 20022 payment instructions -- **gocrwl** (`AGENTS/`) — Go web crawler with containerized deployment -- **koala-ai-stack** (`AGENTS/`) — local AI server infrastructure management -- **klimatkollen** (`XT/`) — Swedish municipal climate data platform - -## Knowledge base — actively use it - -A persistent brain (BM25 search + LLM-synthesised Q&A) survives across sessions, -hosts, and harnesses. It holds 100+ hard-won entries: infra incident postmortems, -Go pitfalls, framework gotchas, design principles, ADRs. **It is not optional -reference material — query it actively, not just when explicitly told.** - -### When to query (treat as a reflex) - -- **Before** starting a non-trivial task — search for prior art with the symptom - AND the system component ("how did we solve X in Y?"). 5 seconds beats 5 hours. -- **When debugging** — search for the error string, the stack frame, the affected - service. Past you may have already paid this tax. -- **Before adopting** a pattern, library, framework, or model name — check if it - was tried and rejected, or what the integration footguns are. -- **When making architectural decisions** — search for the domain + "ADR" or - "decision" to find prior reasoning before re-deriving it. -- **When a recommendation feels novel** — challenge yourself: "has this been - documented?" The brain often has it. - -### When to write - -After you discover something that **future-you would forget** and that **isn't -recoverable from the code, git log, or PR description alone**: - -- Bugs whose root cause is non-obvious and generalisable beyond this project. -- Framework / library / model-name quirks that bit you and would bite anyone. -- Design principles validated under fire (e.g. "every `_get` needs a `_list`"). -- Postmortems for incidents: what broke, why, how diagnosed, what to do next time. - -DON'T write project status, sprint progress, PR summaries, or "what I did this -session" — those rot fast and the originals are in git/gitea anyway. Brain -entries that age well are about *why*, *how to avoid*, and *what to do when*. - -### How to access (per harness) - -| Harness | Query | Write | -|---------|-------|-------| -| **Claude Code, Claude Desktop** | `brain_query` (BM25), `brain_answer` (LLM-synth + sources) MCP tools | `brain_write` MCP tool | -| **Crush, Pi, Antigravity, other MCP-capable** | same MCP server: `ingestion-brain` (via the `mcp__*_brain__*` namespace once authenticated) | same | -| **Anything HTTP-only (curl, scripts)** | `POST https://brain-mcp.d-ma.be/query` with `{"query":"..."}` (auth via `BRAIN_MCP_TOKEN`) | `POST .../write` with `{"content":"...","filename":"..."}` | -| **Browser / human inspection** | `https://gitea.d-ma.be/mathias/hyperguild` → `knowledge/` and `wiki/` markdown files | - -- **Scoping**: defaults to `public` collection; client projects filter to `{client}` + `public`. -- **Routing**: brain_answer's LLM uses berget.ai as primary, iguana ollama as - fallback. Both are configurable in the `supervisor/ingestion-deployment.yaml` - on the koala k3s cluster; don't hardcode local-only model names into the - berget URL (see knowledge entry on namespace mismatches). - -### Quick reflex checks - -If you find yourself about to say any of these out loud, you owe yourself a brain query first: - -- "I think the issue might be..." -- "Let me try X and see..." -- "I'll just write a script to..." -- "This is probably a new bug..." -- "Has anyone done this before?" — *yes, probably, go check.* - -## Client work rules - -When working on a project tagged with a client name: -1. Never send code, data, or context to cloud APIs — use local models only -2. Never reference other client projects or their data -3. Keep all artifacts within the client's git org / directory -4. Treat everything as confidential unless told otherwise - -## Harness-agnostic principles - -This context is designed to work with any AI coding tool: -- Claude Code, Cursor, Aider, Open WebUI, Charmbracelet Mods/Crush -- Pi Coding Agent, Mistral Vibe, Antigravity -- Any tool that accepts a system prompt or reads a markdown context file - -The canonical source is always `.context/AGENT.md` (root) and `.context/PROJECT.md` (per-project). -Derived files are committed (see *How context propagates* below) so a `git pull` on any host yields full agent context with no setup. - -## How context propagates - -Canonical sources of truth: -- Universal: `~/dev/.context/AGENT.md` (this file) -- Project: `/.context/PROJECT.md` (per-repo) - -Derived files (committed, regenerated by `task context:sync`): -- `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `.aider.conventions.md`, - `.context/system-prompt.txt` - -Workflow: -1. Edit a canonical file. Run `task context:sync`. Commit canonical and - derived together. Push. -2. On any other host, `git pull` brings both. Claude Code (tree-walking) - uses `CLAUDE.md`; Crush / Pi / Antigravity (cwd-only) use `AGENTS.md`; - Cursor uses `.cursorrules`; Aider uses `.aider.conventions.md`. -3. `task check` runs `context:sync` then asserts `git status --porcelain` - is empty over the derived files (catches both modified-tracked drift - and missing-untracked adapters). A drift fails the check with a - message telling you to stage the regenerated files. - -Behavior rules in this file and per-project rules in `PROJECT.md` apply -unconditionally on every host, every harness. - -## Engineering Skills - -Shared engineering skills are available in `~/dev/.skills/`. Load on demand via the index. - -See `~/dev/.skills/SKILLS_INDEX.md` for the full list with descriptions and "use when" triggers. - -Key skills: -- **TDD**: always write tests first — load `tdd` skill -- **Code Review**: load `code-review` skill before any review -- **SOLID/Clean Code**: load `solid` or `clean-code` skill for design work -- **Problem first**: load `problem-analysis` skill before coding non-trivial features - ---- - -# __PROJECT_NAME__ - -## Identity - -- **Name**: __PROJECT_NAME__ -- **Owner**: Mathias -- **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ -- **Status**: active - -## Stack - -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. - -## Agent - -TODO: describe what this agent does, what tools it has, and what it's responsible for. - -## Observability - -Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. -Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. - ---- diff --git a/.cursorrules b/.cursorrules deleted file mode 100644 index ec680d6..0000000 --- a/.cursorrules +++ /dev/null @@ -1,258 +0,0 @@ -# Cursor rules — auto-generated -# Do not edit. Run: task context:sync - -# Agent context — Mathias workspace - - - -## Who I am - -I'm Mathias, a digital product manager and technology consultant based in Sweden. -I build software, research emerging tech, and deliver consulting engagements -for clients under NDA. I work across AI/ML, financial automation, web applications, -and climate/sustainability tech. - -## How I work with agents - -- I think like a product manager — I care about *why* before *how* -- I want agents to be opinionated and push back, not just execute blindly -- I prefer concise responses; skip ceremony and get to the point -- When I say "build this", I mean production-quality with tests, not a demo -- Ask me before making irreversible changes or adding heavy dependencies -- I work with confidential client data — never send it to cloud APIs unless I explicitly say it's OK - -## Behavior rules - -These rules apply to every task across every project, regardless of harness. - -1. **No assumptions.** Don't hide confusion — surface it. Surface tradeoffs explicitly. - Think before coding; if the problem is unclear, ask or state assumptions before acting. -2. **Minimum viable code.** Solve with the smallest change that works. Nothing - speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first. -3. **Surgical changes.** Touch only what the task requires. Leave unrelated code, - files, and formatting alone. Diffs should be small and reviewable. -4. **Goal-driven execution.** Define clear success criteria up front for every task. - Loop — implement, verify, refine — until those criteria are met. Don't claim - completion without evidence (tests pass, command output, observed behavior). -5. **Trunk-Based Development — commit directly to main.** Every commit is one - logical change (one tool, one fix, one test) with passing tests. Main is always - deployable. Never create long-lived feature branches. - - **Exception — parallel agents on same repo:** If another agent is known to be - actively working on the same repo simultaneously, create a short-lived branch - (`agent/`), finish the task, and merge to main within the same - session. Do not leave agent branches open between sessions. - - **Exception — external contributor or client four-eyes requirement:** Use - PR flow only when a human reviewer outside the project is required. Document - the reason in PROJECT.md. - -## Default stack - -| Layer | Default | Fallback | Last resort | -|-------|---------|----------|-------------| -| Language | Go | Python | TypeScript, Java, C | -| UI | HTMX + Templ | Server-rendered HTML | React (only if SPA is justified) | -| Build | Task (taskfile.dev) | Make | — | -| Containers | Docker Compose (dev), k3s (prod) | — | — | -| DB | PostgreSQL + sqlc | SQLite | — | -| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — | -| Logging | slog (structured) | — | — | -| Testing | Table-driven, testify | — | — | -| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — | - -Exploratory: Rust, Zig — I'll tell you when I want these. - -## Code conventions - -- **Go style**: golines, gofumpt, golangci-lint -- **Errors**: `fmt.Errorf("operation: %w", err)` — never naked, never log-and-return -- **Naming**: stdlib conventions, no stuttering -- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs -- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), commit directly to main, - one logical change per commit, CI is the quality gate -- **Never**: long-lived feature branches, PRs for solo work, direct push without - passing `task check` locally first -- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config -- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message - -## Infrastructure - -Three machines on Tailscale: - -| Machine | Role | Key specs | -|---------|------|-----------| -| koala | GPU inference, heavy compute | RTX 5070, runs k3s + llama-swap + shared postgres18/pgvector | -| iguana | Services, builds | M2 Ultra Mac | -| flamingo | Daily driver, edge | Mac mini, ~/dev is here | - -- **Model routing**: LiteLLM in front of llama-swap (local) + cloud APIs (when permitted) -- **Orchestration**: k3s cluster across all three machines -- **Networking**: Tailscale mesh - -## Project landscape - -All development repos live at `~/dev/` (softlink from `~/Documents/local-dev/`). - -Organized in thematic folders: - -| Folder | Focus | Count | -|--------|-------|-------| -| `GO/` | Go web frameworks, API integrations, learning projects | ~10 | -| `AI/` | ML research, AI frameworks (FinRL, DSPy, crawl4ai) | ~6 | -| `AGENTS/` | Autonomous agents, coding agents, MCP servers, infra | ~15 | -| `QKX/` | Invoice processing, financial automation, payment systems | ~13 | -| `XT/` | Climate data, sustainability (Klimatkollen, Garbo) | ~2 | - -See `~/dev/PROJECT_SUMMARY.md` for detailed descriptions of each project. - -### Key active projects - -- **super-koala** (`AGENTS/`) — multi-component agent stack with LangGraph, DSPy, MCP -- **azure-tiger** (`QKX/`) — invoice extraction → ISO 20022 payment instructions -- **gocrwl** (`AGENTS/`) — Go web crawler with containerized deployment -- **koala-ai-stack** (`AGENTS/`) — local AI server infrastructure management -- **klimatkollen** (`XT/`) — Swedish municipal climate data platform - -## Knowledge base — actively use it - -A persistent brain (BM25 search + LLM-synthesised Q&A) survives across sessions, -hosts, and harnesses. It holds 100+ hard-won entries: infra incident postmortems, -Go pitfalls, framework gotchas, design principles, ADRs. **It is not optional -reference material — query it actively, not just when explicitly told.** - -### When to query (treat as a reflex) - -- **Before** starting a non-trivial task — search for prior art with the symptom - AND the system component ("how did we solve X in Y?"). 5 seconds beats 5 hours. -- **When debugging** — search for the error string, the stack frame, the affected - service. Past you may have already paid this tax. -- **Before adopting** a pattern, library, framework, or model name — check if it - was tried and rejected, or what the integration footguns are. -- **When making architectural decisions** — search for the domain + "ADR" or - "decision" to find prior reasoning before re-deriving it. -- **When a recommendation feels novel** — challenge yourself: "has this been - documented?" The brain often has it. - -### When to write - -After you discover something that **future-you would forget** and that **isn't -recoverable from the code, git log, or PR description alone**: - -- Bugs whose root cause is non-obvious and generalisable beyond this project. -- Framework / library / model-name quirks that bit you and would bite anyone. -- Design principles validated under fire (e.g. "every `_get` needs a `_list`"). -- Postmortems for incidents: what broke, why, how diagnosed, what to do next time. - -DON'T write project status, sprint progress, PR summaries, or "what I did this -session" — those rot fast and the originals are in git/gitea anyway. Brain -entries that age well are about *why*, *how to avoid*, and *what to do when*. - -### How to access (per harness) - -| Harness | Query | Write | -|---------|-------|-------| -| **Claude Code, Claude Desktop** | `brain_query` (BM25), `brain_answer` (LLM-synth + sources) MCP tools | `brain_write` MCP tool | -| **Crush, Pi, Antigravity, other MCP-capable** | same MCP server: `ingestion-brain` (via the `mcp__*_brain__*` namespace once authenticated) | same | -| **Anything HTTP-only (curl, scripts)** | `POST https://brain-mcp.d-ma.be/query` with `{"query":"..."}` (auth via `BRAIN_MCP_TOKEN`) | `POST .../write` with `{"content":"...","filename":"..."}` | -| **Browser / human inspection** | `https://gitea.d-ma.be/mathias/hyperguild` → `knowledge/` and `wiki/` markdown files | - -- **Scoping**: defaults to `public` collection; client projects filter to `{client}` + `public`. -- **Routing**: brain_answer's LLM uses berget.ai as primary, iguana ollama as - fallback. Both are configurable in the `supervisor/ingestion-deployment.yaml` - on the koala k3s cluster; don't hardcode local-only model names into the - berget URL (see knowledge entry on namespace mismatches). - -### Quick reflex checks - -If you find yourself about to say any of these out loud, you owe yourself a brain query first: - -- "I think the issue might be..." -- "Let me try X and see..." -- "I'll just write a script to..." -- "This is probably a new bug..." -- "Has anyone done this before?" — *yes, probably, go check.* - -## Client work rules - -When working on a project tagged with a client name: -1. Never send code, data, or context to cloud APIs — use local models only -2. Never reference other client projects or their data -3. Keep all artifacts within the client's git org / directory -4. Treat everything as confidential unless told otherwise - -## Harness-agnostic principles - -This context is designed to work with any AI coding tool: -- Claude Code, Cursor, Aider, Open WebUI, Charmbracelet Mods/Crush -- Pi Coding Agent, Mistral Vibe, Antigravity -- Any tool that accepts a system prompt or reads a markdown context file - -The canonical source is always `.context/AGENT.md` (root) and `.context/PROJECT.md` (per-project). -Derived files are committed (see *How context propagates* below) so a `git pull` on any host yields full agent context with no setup. - -## How context propagates - -Canonical sources of truth: -- Universal: `~/dev/.context/AGENT.md` (this file) -- Project: `/.context/PROJECT.md` (per-repo) - -Derived files (committed, regenerated by `task context:sync`): -- `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `.aider.conventions.md`, - `.context/system-prompt.txt` - -Workflow: -1. Edit a canonical file. Run `task context:sync`. Commit canonical and - derived together. Push. -2. On any other host, `git pull` brings both. Claude Code (tree-walking) - uses `CLAUDE.md`; Crush / Pi / Antigravity (cwd-only) use `AGENTS.md`; - Cursor uses `.cursorrules`; Aider uses `.aider.conventions.md`. -3. `task check` runs `context:sync` then asserts `git status --porcelain` - is empty over the derived files (catches both modified-tracked drift - and missing-untracked adapters). A drift fails the check with a - message telling you to stage the regenerated files. - -Behavior rules in this file and per-project rules in `PROJECT.md` apply -unconditionally on every host, every harness. - -## Engineering Skills - -Shared engineering skills are available in `~/dev/.skills/`. Load on demand via the index. - -See `~/dev/.skills/SKILLS_INDEX.md` for the full list with descriptions and "use when" triggers. - -Key skills: -- **TDD**: always write tests first — load `tdd` skill -- **Code Review**: load `code-review` skill before any review -- **SOLID/Clean Code**: load `solid` or `clean-code` skill for design work -- **Problem first**: load `problem-analysis` skill before coding non-trivial features - ---- - -# __PROJECT_NAME__ - -## Identity - -- **Name**: __PROJECT_NAME__ -- **Owner**: Mathias -- **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ -- **Status**: active - -## Stack - -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. - -## Agent - -TODO: describe what this agent does, what tools it has, and what it's responsible for. - -## Observability - -Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. -Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. diff --git a/.context/mcp.json b/.mcp.json similarity index 61% rename from .context/mcp.json rename to .mcp.json index c9514c5..c967ef1 100644 --- a/.context/mcp.json +++ b/.mcp.json @@ -1,9 +1,5 @@ { "mcpServers": { - "knowledge": { - "url": "http://localhost:3100/mcp", - "description": "Project knowledge base — vector + graph retrieval" - }, "brain": { "type": "http", "url": "https://brain-mcp.d-ma.be/mcp", @@ -17,10 +13,6 @@ "headers": { "Authorization": "Bearer ${GITEA_MCP_TOKEN}" } - }, - "infra": { - "type": "http", - "url": "https://infra-mcp.d-ma.be/mcp" } } } diff --git a/AGENTS.md b/AGENTS.md index 42ccd32..cae7f0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,255 +1,44 @@ -# Agent context — Mathias workspace +# __PROJECT_NAME__ — agent context - +Standalone context for agents that read `AGENTS.md` from the repo root. Claude Code uses +`CLAUDE.md` (and tree-walks to `~/dev/CLAUDE.md`); this file mirrors the same essentials for +any other harness. -## Who I am +## Project -I'm Mathias, a digital product manager and technology consultant based in Sweden. -I build software, research emerging tech, and deliver consulting engagements -for clients under NDA. I work across AI/ML, financial automation, web applications, -and climate/sustainability tech. +- **Name**: __PROJECT_NAME__ — a Go agent (ADK + LiteLLM). +- **Owner**: Mathias · **Client**: personal · **Repo**: git.d-ma.be/mathias/__PROJECT_NAME__ -## How I work with agents +## Harness -- I think like a product manager — I care about *why* before *how* -- I want agents to be opinionated and push back, not just execute blindly -- I prefer concise responses; skip ceremony and get to the point -- When I say "build this", I mean production-quality with tests, not a demo -- Ask me before making irreversible changes or adding heavy dependencies -- I work with confidential client data — never send it to cloud APIs unless I explicitly say it's OK +Single harness: **Claude Code + hyperguild** — session-based (start a session, it works, it +stops). There is **no** push-triggered dispatch, listener, or scheduled poller, and none should +be added without a fresh, friction-driven decision. MCP connections in `.mcp.json`: -## Behavior rules +- **brain** (`brain-mcp.d-ma.be`) — knowledge query/write. `BRAIN_MCP_TOKEN`. +- **gitea** (`git-mcp.d-ma.be`) — issues/PRs/repo, the audit trail. `GITEA_MCP_TOKEN`. -These rules apply to every task across every project, regardless of harness. +## Workflow -1. **No assumptions.** Don't hide confusion — surface it. Surface tradeoffs explicitly. - Think before coding; if the problem is unclear, ask or state assumptions before acting. -2. **Minimum viable code.** Solve with the smallest change that works. Nothing - speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first. -3. **Surgical changes.** Touch only what the task requires. Leave unrelated code, - files, and formatting alone. Diffs should be small and reviewable. -4. **Goal-driven execution.** Define clear success criteria up front for every task. - Loop — implement, verify, refine — until those criteria are met. Don't claim - completion without evidence (tests pass, command output, observed behavior). -5. **Trunk-Based Development — commit directly to main.** Every commit is one - logical change (one tool, one fix, one test) with passing tests. Main is always - deployable. Never create long-lived feature branches. +1. **Issue** — work is scoped as a Gitea issue (acceptance criteria + report-back format). +2. **Session** — a Claude Code + hyperguild session does the work in this repo. +3. **PR** — branch off `main`; open a PR; CI (`task check`) is the gate. +4. **Report-back** — comment the outcome on the issue (issue comments are the audit surface). +5. **Brain capture** — persist durable, non-obvious learnings to the brain. - **Exception — parallel agents on same repo:** If another agent is known to be - actively working on the same repo simultaneously, create a short-lived branch - (`agent/`), finish the task, and merge to main within the same - session. Do not leave agent branches open between sessions. +## Conventions - **Exception — external contributor or client four-eyes requirement:** Use - PR flow only when a human reviewer outside the project is required. Document - the reason in PROJECT.md. +- Go: standard tooling; `task check` (lint + vet + `go test -race`) before every PR. +- Errors wrapped (`fmt.Errorf("...: %w", err)`); structured `slog`. +- Trunk-based: commit to `main` via PR; one logical change per commit; CI is the quality gate. +- Secrets via env (`BRAIN_MCP_TOKEN`, `GITEA_MCP_TOKEN`, `LITELLM_API_KEY`); never in code. -## Default stack +## Boundaries -| Layer | Default | Fallback | Last resort | -|-------|---------|----------|-------------| -| Language | Go | Python | TypeScript, Java, C | -| UI | HTMX + Templ | Server-rendered HTML | React (only if SPA is justified) | -| Build | Task (taskfile.dev) | Make | — | -| Containers | Docker Compose (dev), k3s (prod) | — | — | -| DB | PostgreSQL + sqlc | SQLite | — | -| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — | -| Logging | slog (structured) | — | — | -| Testing | Table-driven, testify | — | — | -| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — | - -Exploratory: Rust, Zig — I'll tell you when I want these. - -## Code conventions - -- **Go style**: golines, gofumpt, golangci-lint -- **Errors**: `fmt.Errorf("operation: %w", err)` — never naked, never log-and-return -- **Naming**: stdlib conventions, no stuttering -- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs -- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), commit directly to main, - one logical change per commit, CI is the quality gate -- **Never**: long-lived feature branches, PRs for solo work, direct push without - passing `task check` locally first -- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config -- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message - -## Infrastructure - -Three machines on Tailscale: - -| Machine | Role | Key specs | -|---------|------|-----------| -| koala | GPU inference, heavy compute | RTX 5070, runs k3s + llama-swap + shared postgres18/pgvector | -| iguana | Services, builds | M2 Ultra Mac | -| flamingo | Daily driver, edge | Mac mini, ~/dev is here | - -- **Model routing**: LiteLLM in front of llama-swap (local) + cloud APIs (when permitted) -- **Orchestration**: k3s cluster across all three machines -- **Networking**: Tailscale mesh - -## Project landscape - -All development repos live at `~/dev/` (softlink from `~/Documents/local-dev/`). - -Organized in thematic folders: - -| Folder | Focus | Count | -|--------|-------|-------| -| `GO/` | Go web frameworks, API integrations, learning projects | ~10 | -| `AI/` | ML research, AI frameworks (FinRL, DSPy, crawl4ai) | ~6 | -| `AGENTS/` | Autonomous agents, coding agents, MCP servers, infra | ~15 | -| `QKX/` | Invoice processing, financial automation, payment systems | ~13 | -| `XT/` | Climate data, sustainability (Klimatkollen, Garbo) | ~2 | - -See `~/dev/PROJECT_SUMMARY.md` for detailed descriptions of each project. - -### Key active projects - -- **super-koala** (`AGENTS/`) — multi-component agent stack with LangGraph, DSPy, MCP -- **azure-tiger** (`QKX/`) — invoice extraction → ISO 20022 payment instructions -- **gocrwl** (`AGENTS/`) — Go web crawler with containerized deployment -- **koala-ai-stack** (`AGENTS/`) — local AI server infrastructure management -- **klimatkollen** (`XT/`) — Swedish municipal climate data platform - -## Knowledge base — actively use it - -A persistent brain (BM25 search + LLM-synthesised Q&A) survives across sessions, -hosts, and harnesses. It holds 100+ hard-won entries: infra incident postmortems, -Go pitfalls, framework gotchas, design principles, ADRs. **It is not optional -reference material — query it actively, not just when explicitly told.** - -### When to query (treat as a reflex) - -- **Before** starting a non-trivial task — search for prior art with the symptom - AND the system component ("how did we solve X in Y?"). 5 seconds beats 5 hours. -- **When debugging** — search for the error string, the stack frame, the affected - service. Past you may have already paid this tax. -- **Before adopting** a pattern, library, framework, or model name — check if it - was tried and rejected, or what the integration footguns are. -- **When making architectural decisions** — search for the domain + "ADR" or - "decision" to find prior reasoning before re-deriving it. -- **When a recommendation feels novel** — challenge yourself: "has this been - documented?" The brain often has it. - -### When to write - -After you discover something that **future-you would forget** and that **isn't -recoverable from the code, git log, or PR description alone**: - -- Bugs whose root cause is non-obvious and generalisable beyond this project. -- Framework / library / model-name quirks that bit you and would bite anyone. -- Design principles validated under fire (e.g. "every `_get` needs a `_list`"). -- Postmortems for incidents: what broke, why, how diagnosed, what to do next time. - -DON'T write project status, sprint progress, PR summaries, or "what I did this -session" — those rot fast and the originals are in git/gitea anyway. Brain -entries that age well are about *why*, *how to avoid*, and *what to do when*. - -### How to access (per harness) - -| Harness | Query | Write | -|---------|-------|-------| -| **Claude Code, Claude Desktop** | `brain_query` (BM25), `brain_answer` (LLM-synth + sources) MCP tools | `brain_write` MCP tool | -| **Crush, Pi, Antigravity, other MCP-capable** | same MCP server: `ingestion-brain` (via the `mcp__*_brain__*` namespace once authenticated) | same | -| **Anything HTTP-only (curl, scripts)** | `POST https://brain-mcp.d-ma.be/query` with `{"query":"..."}` (auth via `BRAIN_MCP_TOKEN`) | `POST .../write` with `{"content":"...","filename":"..."}` | -| **Browser / human inspection** | `https://gitea.d-ma.be/mathias/hyperguild` → `knowledge/` and `wiki/` markdown files | - -- **Scoping**: defaults to `public` collection; client projects filter to `{client}` + `public`. -- **Routing**: brain_answer's LLM uses berget.ai as primary, iguana ollama as - fallback. Both are configurable in the `supervisor/ingestion-deployment.yaml` - on the koala k3s cluster; don't hardcode local-only model names into the - berget URL (see knowledge entry on namespace mismatches). - -### Quick reflex checks - -If you find yourself about to say any of these out loud, you owe yourself a brain query first: - -- "I think the issue might be..." -- "Let me try X and see..." -- "I'll just write a script to..." -- "This is probably a new bug..." -- "Has anyone done this before?" — *yes, probably, go check.* - -## Client work rules - -When working on a project tagged with a client name: -1. Never send code, data, or context to cloud APIs — use local models only -2. Never reference other client projects or their data -3. Keep all artifacts within the client's git org / directory -4. Treat everything as confidential unless told otherwise - -## Harness-agnostic principles - -This context is designed to work with any AI coding tool: -- Claude Code, Cursor, Aider, Open WebUI, Charmbracelet Mods/Crush -- Pi Coding Agent, Mistral Vibe, Antigravity -- Any tool that accepts a system prompt or reads a markdown context file - -The canonical source is always `.context/AGENT.md` (root) and `.context/PROJECT.md` (per-project). -Derived files are committed (see *How context propagates* below) so a `git pull` on any host yields full agent context with no setup. - -## How context propagates - -Canonical sources of truth: -- Universal: `~/dev/.context/AGENT.md` (this file) -- Project: `/.context/PROJECT.md` (per-repo) - -Derived files (committed, regenerated by `task context:sync`): -- `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, `.aider.conventions.md`, - `.context/system-prompt.txt` - -Workflow: -1. Edit a canonical file. Run `task context:sync`. Commit canonical and - derived together. Push. -2. On any other host, `git pull` brings both. Claude Code (tree-walking) - uses `CLAUDE.md`; Crush / Pi / Antigravity (cwd-only) use `AGENTS.md`; - Cursor uses `.cursorrules`; Aider uses `.aider.conventions.md`. -3. `task check` runs `context:sync` then asserts `git status --porcelain` - is empty over the derived files (catches both modified-tracked drift - and missing-untracked adapters). A drift fails the check with a - message telling you to stage the regenerated files. - -Behavior rules in this file and per-project rules in `PROJECT.md` apply -unconditionally on every host, every harness. - -## Engineering Skills - -Shared engineering skills are available in `~/dev/.skills/`. Load on demand via the index. - -See `~/dev/.skills/SKILLS_INDEX.md` for the full list with descriptions and "use when" triggers. - -Key skills: -- **TDD**: always write tests first — load `tdd` skill -- **Code Review**: load `code-review` skill before any review -- **SOLID/Clean Code**: load `solid` or `clean-code` skill for design work -- **Problem first**: load `problem-analysis` skill before coding non-trivial features - ---- - -# __PROJECT_NAME__ - -## Identity - -- **Name**: __PROJECT_NAME__ -- **Owner**: Mathias -- **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ -- **Status**: active - -## Stack - -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. - -## Agent - -TODO: describe what this agent does, what tools it has, and what it's responsible for. +Runtime scope (network egress allow-list, file scope, approved operations, failure posture) is +in `AGENT_BOUNDARIES.md`. Read it before adding tools, endpoints, or write access. ## Observability -Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. -Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. +Traces → Jaeger via `OTLP_ENDPOINT`; `ADK_SERVICE_NAME=__PROJECT_NAME__`. Spans: `invoke_agent`, +`generate_content`. diff --git a/AGENT_BOUNDARIES.md b/AGENT_BOUNDARIES.md index d640fef..8097b72 100644 --- a/AGENT_BOUNDARIES.md +++ b/AGENT_BOUNDARIES.md @@ -22,7 +22,9 @@ Egress MUST be blocked to: - Public package registries from runtime (proxy through build only) - Customer/client domains not listed in the engagement scope -Add new endpoints by editing `agent-policy.yaml` AND this table in the same commit. +Add new endpoints by editing this table in the same commit that wires them, and enforce them +with whatever egress mechanism the deployment uses (e.g. a k8s NetworkPolicy in the project's +own deploy manifests). ## File scope @@ -68,7 +70,7 @@ The agent MUST NOT, without explicit opt-in in code review: ## Review triggers -Bump this doc + `agent-policy.yaml` when: +Bump this doc (and the deployment's egress enforcement) when: - A new external endpoint is added - A new tool with side effects is wired in diff --git a/CLAUDE.md b/CLAUDE.md index b69a2a8..021e620 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,18 +5,38 @@ - **Name**: __PROJECT_NAME__ - **Owner**: Mathias - **Client**: personal -- **Repo**: gitea.d-ma.be/mathias/__PROJECT_NAME__ +- **Repo**: git.d-ma.be/mathias/__PROJECT_NAME__ - **Status**: active ## Stack -Go + ADK + LiteLLM. See `~/dev/.context/AGENT.md` for cross-project conventions. +Go + ADK + LiteLLM. Claude Code tree-walks to `~/dev/CLAUDE.md` for cross-project conventions. ## Agent TODO: describe what this agent does, what tools it has, and what it's responsible for. +## Harness & workflow + +Single harness: **Claude Code + hyperguild** — session-based (you start a session, it works, +it stops; there is no push-triggered dispatch). MCP connections are in `.mcp.json`: **brain** +(knowledge query/write) and **gitea** (issues/PRs/repo — the audit trail). Provide +`BRAIN_MCP_TOKEN` and `GITEA_MCP_TOKEN` in the environment. + +The loop for a unit of work: + +1. **Issue** — the work is a Gitea issue (scope, acceptance criteria, report-back format). +2. **Session** — a Claude Code + hyperguild session does the work in this repo. +3. **PR** — branch off `main`, open a PR; CI (`task check`) is the gate. +4. **Report-back** — comment the outcome on the issue (issue comments are the audit surface). +5. **Brain capture** — if a learning is durable and non-obvious, write it to the brain. + ## Observability Traces → Jaeger via `OTLP_ENDPOINT`. Set `ADK_SERVICE_NAME=__PROJECT_NAME__` per deployment. Spans emitted: `invoke_agent`, `generate_content`. Tool spans require custom callbacks. + +## Boundaries + +Runtime scope (network egress, file scope, approved operations) is in `AGENT_BOUNDARIES.md` — +read it before adding tools, endpoints, or write access. diff --git a/README.md b/README.md index 99ca285..fd23b10 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,16 @@ go mod tidy task run ``` +## Harness & workflow + +Single harness: **Claude Code + hyperguild** — session-based (start a session, it works, it +stops). No push-triggered dispatch. MCP connections live in `.mcp.json`: **brain** (knowledge) +and **gitea** (issues/PRs — the audit trail); provide `BRAIN_MCP_TOKEN` and `GITEA_MCP_TOKEN`. + +Work flows: **issue → hyperguild session → PR (`task check` gate) → report-back comment on the +issue → brain capture if the learning is durable**. See `AGENTS.md` / `CLAUDE.md` for the full +context, `AGENT_BOUNDARIES.md` for runtime scope. + ## Observability Set `OTLP_ENDPOINT=http://jaeger.d-ma.be:4318` to emit traces. Each invocation produces: diff --git a/Taskfile.yml b/Taskfile.yml index 2767af8..d9a0e8c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -23,14 +23,3 @@ tasks: - golangci-lint run ./... - go vet ./... - go test ./... -race -count=1 - - context:sync: - desc: Regenerate all harness-specific context files - cmds: - - bash scripts/context-sync.sh - context:sync:claude: - cmds: [bash scripts/context-sync.sh claude] - context:sync:agents: - cmds: [bash scripts/context-sync.sh agents] - context:sync:cursor: - cmds: [bash scripts/context-sync.sh cursor] diff --git a/agent-policy.yaml b/agent-policy.yaml deleted file mode 100644 index 8f71478..0000000 --- a/agent-policy.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# NetworkPolicy for __PROJECT_NAME__. -# -# Pairs with AGENT_BOUNDARIES.md. Egress is allow-listed: LiteLLM, brain-mcp, -# gitea-mcp, OTLP collector, in-cluster DNS. Everything else is denied. -# -# Apply in the __PROJECT_NAME__ namespace. Substitute __PROJECT_NAME__ at -# render time (envsubst, kustomize replacement, or sed in CI). ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: __PROJECT_NAME__-egress - namespace: __PROJECT_NAME__ - labels: - app.kubernetes.io/name: __PROJECT_NAME__ - app.kubernetes.io/component: agent -spec: - podSelector: - matchLabels: - app.kubernetes.io/name: __PROJECT_NAME__ - policyTypes: - - Egress - egress: - # In-cluster DNS — required for resolving any of the endpoints below. - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - # LiteLLM — model inference proxy. - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: litellm - podSelector: - matchLabels: - app.kubernetes.io/name: litellm - ports: - - protocol: TCP - port: 4000 - - # Brain MCP — knowledge base query/write. - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: ingestion - podSelector: - matchLabels: - app.kubernetes.io/name: brain-mcp - ports: - - protocol: TCP - port: 8080 - - # Gitea MCP — repo/issue/PR access. - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: gitea - podSelector: - matchLabels: - app.kubernetes.io/name: gitea-mcp - ports: - - protocol: TCP - port: 8080 - - # OTLP — trace export to Jaeger collector. - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability - podSelector: - matchLabels: - app.kubernetes.io/name: jaeger - ports: - - protocol: TCP - port: 4318 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: __PROJECT_NAME__-default-deny - namespace: __PROJECT_NAME__ - labels: - app.kubernetes.io/name: __PROJECT_NAME__ -spec: - podSelector: - matchLabels: - app.kubernetes.io/name: __PROJECT_NAME__ - policyTypes: - - Ingress - - Egress - # Empty rules = deny-all. The allow-list above is additive on Egress. - # Ingress stays denied unless a sibling policy opens specific ports. diff --git a/scripts/context-sync.sh b/scripts/context-sync.sh deleted file mode 100755 index 4f7300e..0000000 --- a/scripts/context-sync.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env bash -# Generates harness-specific context files from .context/PROJECT.md -# Project-level script — run from a project directory. -# -# For Claude Code: generates project-only CLAUDE.md (it inherits root via tree walk) -# For everything else: concatenates root AGENT.md + project PROJECT.md -# -# Usage: ./scripts/context-sync.sh [--force] [adapter...] -# Task: task context:sync -# -# Override root context: ROOT_CONTEXT=~/dev/.context/AGENT.md ./scripts/context-sync.sh - -set -euo pipefail - -# Parse --force flag and collect adapter names separately -FORCE=false -ADAPTERS=() -for _arg in "$@"; do - case "$_arg" in - --force) FORCE=true ;; - *) ADAPTERS+=("$_arg") ;; - esac -done - -PROJECT_FILE=".context/PROJECT.md" - -# Walk up to find root .context/AGENT.md -find_root_context() { - local dir - dir="$(pwd)" - while [ "$dir" != "/" ]; do - dir="$(dirname "$dir")" - if [ -f "$dir/.context/AGENT.md" ]; then - echo "$dir/.context/AGENT.md" - return - fi - done - echo "" -} - -ROOT_CONTEXT="${ROOT_CONTEXT:-$(find_root_context)}" - -if [ ! -f "$PROJECT_FILE" ]; then - echo "Error: $PROJECT_FILE not found. Are you in a project root?" - exit 1 -fi - -# Pre-flight: reject unfilled {{...}} placeholders unless --force -if [ "$FORCE" = false ]; then - _placeholders=$(grep -n '{{[^}]*}}' "$PROJECT_FILE" 2>/dev/null || true) - if [ -n "$_placeholders" ]; then - echo "Error: unfilled placeholders in $PROJECT_FILE:" >&2 - while IFS= read -r _match; do - _lineno="${_match%%:*}" - _content="${_match#*:}" - _token=$(printf '%s' "$_content" | grep -o '{{[^}]*}}' | head -1) - echo " $PROJECT_FILE:$_lineno: unfilled placeholder $_token" >&2 - done <<< "$_placeholders" - echo "" >&2 - echo "Fill these placeholders, then re-run: task context:sync" >&2 - echo "To bypass validation: bash scripts/context-sync.sh --force" >&2 - exit 1 - fi -fi - -if [ -n "$ROOT_CONTEXT" ] && [ -f "$ROOT_CONTEXT" ]; then - echo " Root context: $ROOT_CONTEXT" -else - echo " No root AGENT.md found (project context only)" -fi - -# Emit root context + separator -root_block() { - if [ -n "$ROOT_CONTEXT" ] && [ -f "$ROOT_CONTEXT" ]; then - cat "$ROOT_CONTEXT" - echo "" - echo "---" - echo "" - fi -} - -# ── Claude Code ────────────────────────────────────────────── -# Claude Code walks up the tree — it finds ~/dev/CLAUDE.md automatically. -# Project-level CLAUDE.md only needs project-specific context. -generate_claude() { - cat "$PROJECT_FILE" > CLAUDE.md - echo " → CLAUDE.md (project-only; Claude Code inherits root)" -} - -# ── AGENTS.md (Crush, Pi, Antigravity) ────────────────────── -# These tools read AGENTS.md from cwd but don't walk up. -# Concatenate root + project. -generate_agents() { - { root_block; cat "$PROJECT_FILE"; } > AGENTS.md - echo " → AGENTS.md (root + project; Crush, Pi, Antigravity)" -} - -# ── Cursor ─────────────────────────────────────────────────── -generate_cursor() { - { - echo "# Cursor rules — auto-generated" - echo "# Do not edit. Run: task context:sync" - echo "" - root_block - cat "$PROJECT_FILE" - } > .cursorrules - echo " → .cursorrules (root + project)" -} - -# ── Aider ──────────────────────────────────────────────────── -generate_aider() { - { root_block; cat "$PROJECT_FILE"; } > .aider.conventions.md - if [ ! -f .aider.conf.yml ]; then - cat > .aider.conf.yml << 'YAML' -read: .aider.conventions.md -auto-commits: false -YAML - fi - echo " → .aider.conventions.md (root + project)" -} - -# ── Generic system prompt (Open WebUI, Mods, etc.) ────────── -generate_system_prompt() { - { - echo "You are a coding assistant working on a specific project." - echo "Follow all conventions from both the root agent context and project context." - echo "" - echo "---" - echo "" - root_block - cat "$PROJECT_FILE" - echo "" - echo "---" - } > .context/system-prompt.txt - echo " → .context/system-prompt.txt (root + project)" -} - -# ── MCP config ─────────────────────────────────────────────── -generate_mcp() { - # Ensure baseline file exists with project-specific knowledge server - if [ ! -f .context/mcp.json ]; then - cat > .context/mcp.json << 'JSON' -{ - "mcpServers": { - "knowledge": { - "url": "http://localhost:3100/mcp", - "description": "Project knowledge base — vector + graph retrieval" - } - } -} -JSON - fi - - # Merge root mcp-servers.json if found alongside root AGENT.md - local root_mcp="" - if [ -n "$ROOT_CONTEXT" ] && [ -f "$ROOT_CONTEXT" ]; then - local candidate - candidate="$(dirname "$ROOT_CONTEXT")/mcp-servers.json" - [ -f "$candidate" ] && root_mcp="$candidate" - fi - - if [ -z "$root_mcp" ]; then - echo " → .context/mcp.json (exists, no root mcp-servers.json found)" - return - fi - - # Root servers take precedence over project entries on key conflict - local root_servers count updated - root_servers=$(jq '.servers' "$root_mcp") - count=$(printf '%s' "$root_servers" | jq 'keys | length') - updated=$(jq --argjson root "$root_servers" \ - '.mcpServers = (.mcpServers + $root)' \ - .context/mcp.json) - printf '%s\n' "$updated" > .context/mcp.json - echo " → .context/mcp.json (merged $count root servers)" -} - -echo "Syncing project context from $PROJECT_FILE..." - -if [ ${#ADAPTERS[@]} -eq 0 ]; then - generate_claude - generate_agents - generate_cursor - generate_aider - generate_system_prompt - generate_mcp -else - for adapter in "${ADAPTERS[@]}"; do - case "$adapter" in - claude) generate_claude ;; - agents) generate_agents ;; - cursor) generate_cursor ;; - aider) generate_aider ;; - prompt|system|openwebui|owui|generic) generate_system_prompt ;; - mcp) generate_mcp ;; - *) echo "Unknown adapter: $adapter" >&2; exit 1 ;; - esac - done -fi - -echo "Done."