129 added, 170 removed. Audit A to A.
- # Aiden v4.0.0 — AGENTS.md
-
- ## Sprint context
- - Branch: `v4-rewrite` (NEVER push to main during this sprint)
- - v3.19.9 stays live on npm/GitHub. `main` branch frozen.
- - Reference architecture: `docs/v4.0.0-architecture.md` (READ FIRST)
- - Sprint progress: `docs/sprint/phase-N-completed.md` (read previous phase before starting next)
+ # AGENTS.md — Aiden agent contract
- ## Mission
- Aiden v4.0.0 = Hermes-grade everything (architecture, tooling, skills, memory, security, UX) + Aiden's unique layer (honesty enforcement, Pro tier, OAuth subscriptions, native Windows, npm distribution).
+ The contract the Aiden agent honours on every turn, and the public surface
+ it exposes for callers (CLI, OpenAI-compatible HTTP API, channel adapters).
- Single-loop agent replaces planner+responder split. ONE LLM. Tools called inside loop. Architecture prevents fabrication by design.
+ ---
- ## Key paths
- - Aiden repo: `C:\Users\shiva\DevOS`
- - Aiden user data (runtime): `%LOCALAPPDATA%\aiden\`
- - Hermes reference (read-only): `C:\Users\shiva\references\hermes-agent` (branch `aiden-v4-reference`)
- - Architecture doc: `docs/v4.0.0-architecture.md`
- - Sprint progress: `docs/sprint/`
+ ## What the agent is
- ## Working style
- - Author all commits as Shiva Deore. NO Co-Authored-By Claude. NO "Generated with Claude Code" trailers.
- - Conventional commit format: `type(scope): description`
- - Phased delivery. Each phase leaves runnable build. Stop and ask if uncertain.
- - No fabrication. No silent workarounds. Stop and report.
+ Aiden is a **single-loop tool-calling agent** with a 90-turn cap. Every
+ turn:
- ### Hermes-first rule (non-negotiable)
+ 1. Build / refresh the system prompt (8-slot composition: SOUL → personality
+ → memory → user → skills → llama-hint → budget → environment).
+ 2. Send the conversation + tool schemas to the active provider.
+ 3. If the provider returns a tool-use response → dispatch each tool call
+ sequentially through the injected `toolExecutor`, append the results
+ as `tool` messages, loop.
+ 4. If the provider returns a final assistant message → exit the loop.
- When anything in Aiden doesn't work as expected or needs new functionality —
- UX, prompts, identity, errors, onboarding, tool behavior, browser automation,
- memory, sessions, MCP, providers, fallback chains, streaming, security gates,
- plugins, OAuth, cron, gateway, voice, ACP, delegation, ANY functional surface —
- the agent MUST audit how Hermes solves it before writing code.
+ There is **no planner / responder split**. There is **no subagent fanout**.
+ The single-loop architecture prevents fabrication by design: the model
+ either calls a tool or it ends the turn — there is no third "imagine the
+ result" path.
- Reference: `C:\Users\shiva\references\hermes-agent` (read-only, graphify-mapped).
+ Source: `core/v4/aidenAgent.ts`.
- Process for every fix or new feature:
- 1. Reproduce/scope the problem in Aiden.
- 2. Find the equivalent surface in Hermes:
- - `graphify query "<topic keywords>"`
- - Read the relevant Hermes source
- 3. Output a 1-page audit at `docs/sprint/hermes-<topic>-audit.md`:
- - File refs (`path:line`) for each Hermes pattern
- - 2–3 line summary of Hermes's approach
- - Decision: copy / adapt / diverge with explicit reason
- 4. Only then implement.
+ ---
- If Hermes does NOT solve the problem, document that in the audit and proceed
- with original design.
+ ## Public API
- Never reinvent a wheel Hermes already shipped. Every divergence requires a
- written reason. Phases that skip the audit must be redone.
+ ```ts
+ class AidenAgent {
+ constructor(opts: AidenAgentOptions)
+ setProvider(adapter: ProviderAdapter): void
+ invalidateSystemPromptCache(): void
+ setPersonalityOverlay(overlay: string | undefined): boolean
+ getSystemPromptForDebug(): Promise<string | null>
+ markMemoryDirty(file: 'memory' | 'user'): void
+ getMemoryDirtyState(): 'memory' | 'user' | 'both' | null
+ runConversation(history: Message[], opts?: RunConversationOptions): Promise<AidenAgentResult>
+ }
+ ```
- ## Token-efficient working pattern (every phase)
- 1. Read previous phase summary: `docs/sprint/phase-N-1-completed.md`
- 2. Use `graphify query "..."` BEFORE reading files (200 tokens vs 5000+ for file reads)
- 3. Read only files explicitly listed as needed in the phase prompt
- 4. Commit after each subtask (forces context cleanup, hook updates graph)
- 5. Write `docs/sprint/phase-N-completed.md` at end of phase (under 200 lines)
- 6. Run `/clear` between phases when Shiva says so
+ `AidenAgentResult` carries `finalContent`, `messages`, `turnCount`,
+ `toolCallCount`, `fallbackActivated`, `finishReason ∈ {stop, budget_exhausted, error}`,
+ `totalUsage`, `toolCallTrace`, `honestyFindings?`, `skillCreated?`,
+ `compressionEvents`, `auxiliaryUsage`, `skillEnforcement`, `urlProvenance`,
+ `emptyResponse`.
- ## Graphify usage
- - Aiden graph: `cd C:\Users\shiva\DevOS && graphify query "..."`
- - Hermes graph: `cd C:\Users\shiva\references\hermes-agent && graphify query "..."`
- - Hooks fire on every commit; graph stays fresh automatically.
- - Windows hook patch: `.git/hooks/post-commit` + `post-checkout` use uv-managed python at `/c/Users/shiva/AppData/Roaming/uv/tools/graphifyy/Scripts/python.exe`. Re-apply if `graphify hook install` is rerun.
+ ---
- ## What v4 KEEPS from v3.19.x
- 86 tool implementations, Pro license + Cloudflare KV (`devos-license-server`), npm dual-package (`aiden-runtime` + `aiden-os`), plugin system, 40 bundled skills, provider chain (4 Groq + 4 Gemini + 3 OR + Ollama), C7/C8 safety, PlannerGuard concept, MemoryGuard concept, SkillTeacher concept, all 12 fixes from v3.19.5–v3.19.9, SOUL.md, native Windows support.
+ ## Honesty contract (the moat)
- ## What v4 DELETES
- - `planWithLLM()` in `core/agentLoop.ts` (~1500 LOC) — confirmed via graphify (community 0, L838)
- - `respondWithResults()` in `core/agentLoop.ts` (~800 LOC) — confirmed via graphify (community 0, L2681)
- - Glue between them (~2700 LOC)
- - `direct_response` fast-path
- - Replan logic, multi-Q parallel handling
- - C20/C21 fabrication band-aids (architecture replaces them)
- - `workspace/semantic.json` (replaced by SQLite + FTS5)
+ Every turn is gated by a 10-module security and verification layer
+ (`moat/`):
- ## Testing requirements (every phase)
- - Each phase has acceptance criteria — verify them, don't claim completion without tests passing.
- - Run `npm test` (or equivalent) before committing.
- - New code requires new tests where applicable.
- - No phase advances with known regressions.
+ | Module | Role |
+ |---|---|
+ | `approvalEngine.ts` | tier the tool call (`safe` / `caution` / `dangerous`) and consult the user when needed |
+ | `dangerousPatterns.ts` | classify shell commands; refuse the obviously-bad ones |
+ | `honestyEnforcement.ts` | post-loop scan: if the assistant claims a tool succeeded but the trace says it failed, rewrite the claim |
+ | `memoryGuard.ts` | reject `memory_add` when the value isn't backed by tool evidence |
+ | `plannerGuard.ts` | narrow the offered tools by intent, prevent prompt-bloat |
+ | `proLicense.ts` | gate Pro features |
+ | `providerChain.ts` | provider chain glue |
+ | `skillTeacher.ts` | propose a new skill (tier-3) or auto-create one (tier-4) when a multi-step success qualifies |
+ | `ssrfProtection.ts` | block private/loopback URLs from web tools |
+ | `tirithScanner.ts` | secret/PII pre-write scan on `file_write` and `file_patch` |
- ### Integration test provider fallback
+ Together these are the difference between "an LLM with tools" and "an
+ agent that's safe to leave running".
- Integration tests that need a real LLM use `getTestProvider()` from
- `tests/v4/_helpers/testProvider.ts` instead of hardcoding `GROQ_API_KEY`.
- The fallback chain is:
+ ---
- 1. `GROQ_API_KEY` — primary, free tier, fast
- 2. `GROQ_API_KEY_2` — secondary Groq account
- 3. `GROQ_API_KEY_3` — tertiary Groq account
- 4. `TOGETHER_API_KEY` — paid fallback (~$10 sprint budget — use sparingly)
+ ## Provider fallback
- Tests skip cleanly only when **all four** are missing. Wrap test bodies
- with `withRateLimitFallback(fn, initialProvider)` to auto-retry on 429s
- across the chain — non-rate-limit errors propagate immediately so real
- bugs aren't hidden.
+ `core/v4/providerFallback.ts`. 6-slot self-healing chain
+ (`together → together-fallback → groq × 4`). On rate-limit (429), the
+ adapter advances to the next slot in under a second; on success, the
+ slot's cooldown is cleared and the chain returns to baseline.
- Provider-specific adapter tests (`chatCompletionsAdapter.groq`,
- `chatCompletionsAdapter.together`, `runtimeResolver.real`) intentionally
- do NOT use the helper — they pin a specific provider on purpose.
+ The agent never sees provider failures — fallback is transparent. The
+ result's `fallbackActivated: true` flag tells callers a slot advance
+ happened on this turn.
- Optional model overrides: `GROQ_TEST_MODEL`, `TOGETHER_TEST_MODEL`.
+ ---
- ## Common gotchas
- - `PACKAGE_ROOT` (npm install dir) vs `WORKSPACE_ROOT` (user data dir) — conflating these caused 3 failed releases.
- - npm dual-package atomic publish: `npm run release:npm` (`scripts/release-npm.ps1`).
- - `AIDEN_CLI_MODE=1` set by `bin/aiden.js` auto-suppresses bracket-prefixed `console.log` when level >= warn.
- - Together-1 provider disabled (HTTP 400 cascade since v3.19.5).
- - Windows graphify hooks need patched python path (see above).
- - Setup wizard validates API keys against provider endpoints before saving. Smoke-test mode (`--smoke-test`) and `--skip-validation` flag both bypass.
+ ## Memory
- ## Git remotes (CRITICAL — read before pushing)
- - `origin` = public repo, FROZEN at v3.19.9 during this sprint. Never push to origin.
- - `backup` = private repo (taracodlabs/Aiden-v4), ALL v4 work pushes here.
- - `v4-rewrite` branch is configured to default-push to `backup` only.
- - Public release happens later by merging backup/v4-rewrite into origin/main as one big release.
+ Multi-layer:
- ## v4 CLI UX — design targets for Phase 14c
+ - `MEMORY.md` — declarative facts the user has confirmed
+ - `USER.md` — user identity, preferences, projects (re-read every turn)
+ - `SOUL.md` — Aiden's identity (re-read every turn)
+ - `LESSONS.md` — failure trace, written by the learning-memory module
+ - conversation / session / workspace memory — per-context history
+ - semantic memory — BM25 + embeddings over the recall layers
- The chat REPL in 14c implements three signature UX elements. These were locked in after reviewing Hermes's interface and choosing what's worth adopting:
+ Dirty-bit invalidation: when a tool writes to `MEMORY.md` or `USER.md`,
+ the agent calls `markMemoryDirty()`. The next turn rebuilds the system
+ prompt from disk; subsequent turns use the cached prompt until the bit
+ flips again.
- ### 1. Boxed startup card (rendered once when chat session opens)
+ ---
- ```
- █████╗ ██╗██████╗ ███████╗███╗ ██╗
- ██╔══██╗██║██╔══██╗██╔════╝████╗ ██║
- ███████║██║██║ ██║█████╗ ██╔██╗ ██║
- ██╔══██║██║██║ ██║██╔══╝ ██║╚██╗██║
- ██║ ██║██║██████╔╝███████╗██║ ╚████║
- ╚═╝ ╚═╝╚═╝╚═════╝ ╚══════╝╚═╝ ╚═══╝
+ ## What the agent will not do
- ╭─────────────────────────────────────────────────────────────────╮
- │ Aiden v4.0.0 · Taracod │
- │ │
- │ Available Tools │
- │ files: read, write, patch, delete, move, copy │
- │ web: search, fetch, deep_research │
- │ browser: navigate, click, type, screenshot, ... │
- │ terminal: shell_exec (local + docker) │
- │ memory: add, replace, remove │
- │ sessions: search, list │
- │ process: spawn, kill, log_read, list, wait │
- │ skills: list, view, manage │
- │ (and N more toolsets...) │
- │ │
- │ Available Skills │
- │ <category>: <skill1>, <skill2>, ... (truncated to fit) │
- │ ... <total> skills across <category-count> categories │
- │ │
- │ <provider> · <model> │
- │ Session: <session-id> │
- │ │
- │ <tool-count> tools · <skill-count> skills · /help for commands │
- ╰─────────────────────────────────────────────────────────────────╯
- ```
+ - Fabricate a tool result (architecture prevents it: model either calls
+ the tool or ends the turn).
+ - Run a `dangerous`-tier shell command without explicit approval, even in
+ `/yolo` mode (yolo lowers the bar, doesn't remove it).
+ - Send PII or secrets to a provider when `tirithScanner` flags the body
+ pre-write.
+ - Visit private/loopback URLs from a web tool (SSRF guard).
+ - Claim a tool succeeded when the trace says it didn't (honesty
+ enforcement post-loop scan rewrites the claim).
- Banner in brand orange `#FF6B35`. Box border in dim gray. Tool/skill names in default. Headers ("Available Tools", "Available Skills") in bold orange.
+ ---
- ### 2. Status line (bottom of input area, always visible)
+ ## What the agent will do
- Format:
- ```
- $ <provider>:<model> ctx <used>/<max> [<progress-bar>] budget <used>/<max> <session-age>
- ```
+ - Keep going on rate-limits — fallback chain advances slots under a
+ second, the user only sees the final answer.
+ - Surface every failure with the tool, provider, retry count, fallback
+ chain, error, and next step. No silent swallowing.
+ - Refresh `MEMORY.md` / `USER.md` / `SOUL.md` mid-session when the user
+ edits them — no restart required.
+ - Write a new skill when a multi-step success qualifies (tier-3 propose
+ or tier-4 auto, depending on `skill_teacher_tier` in config).
+ - Stream tokens to the originating channel (CLI, HTTP, Discord, Slack,
+ WhatsApp, Email, Webhook, Twilio, iMessage, Signal).
- Example:
- ```
- $ groq:llama-3.3-70b-versatile ctx 4.2k/200k [▓░░░░░░░░░] 2% budget 3/90 3m
- ```
+ ---
- Updates after each turn. Renders below user input prompt, above the next available input line. Use box-drawing chars for separator.
+ ## Adding a new tool
- ### 3. Slash command autocomplete dropdown
+ 1. Create `tools/v4/<category>/<name>.ts` exporting a `ToolDefinition`.
+ 2. Add the import + `registry.register(myTool)` to `tools/v4/index.ts`.
+ 3. Add a unit test in `tests/v4/tools/`.
+ 4. If the tool mutates state, set `mutates: true` and add the dangerous
+ patterns the approval engine should flag.
- When user types `/` in the chat input, show a filterable dropdown:
+ The tool is automatically advertised to every provider that supports
+ tool calling.
- ```
- /provider _
- ─────────────────────────────────────────────────────────────────
- /profile Show active profile name and home directory
- /provider Show available providers and current provider
- /personality Set a predefined personality (usage: /personality [name])
- /plugins List installed plugins and their status
- /paste Check clipboard for an image and attach it
- ⚡ /trading-alert NSE swing trading alert workflow
- ⚡ /research Multi-source web research with summary
- ```
+ ---
- System slash commands: no icon, default color.
- Skill slash commands: `⚡` prefix in orange, name in default. (Skill commands come from Phase 10's `skillCommands.buildCommandMap()`.)
+ ## Adding a new provider
- Filter as user types. Arrow keys navigate. Enter selects. Esc dismisses.
+ 1. Create `providers/v4/<name>Adapter.ts` implementing `ProviderAdapter`
+ (`call(req)`, `callStream(req)`, `apiMode`).
+ 2. Add the registry entry in `providers/v4/registry.ts` with `id`,
+ `displayName`, `apiMode`, `baseUrl`, `apiKeyEnvVar`, `tier`.
+ 3. Add the model IDs to `providers/v4/modelCatalog.ts`.
+ 4. Add a smoke test in `tests/v4/providers/`.
- ### 4. Inline error display
+ The runtime resolver picks both up automatically — no other edits needed.
- Errors render with actionable suggestion below:
- ```
- Unknown provider 'groq'. Run aiden model to pick a valid provider,
- or aiden doctor to diagnose config issues.
- ```
+ ---
- Red text for the error line, dim gray for the suggestion. No stack traces shown to user (logged separately).
+ ## Testing
- ### Implementation notes for Phase 14c agent
+ ```bash
+ npm test # vitest, ~1,500 unit + integration tests
+ npm run typecheck # tsc --noEmit
+ npm run build # esbuild bundle
+ ```
- - Boxed card uses live data from RuntimeResolver (provider/model), SessionManager (session ID), ToolRegistry (tool count), SkillLoader (skill count)
- - Status line updates via callback hooks already wired in Phase 13 (onCompression, onBudgetWarning, totalUsage tracking)
- - Autocomplete dropdown can use `@inquirer/prompts` `search` prompt OR a custom prompt-toolkit-style overlay — agent's call based on what renders cleanly on Windows Terminal
- - Skill slash commands list comes from `core/v4/skillCommands.ts` `buildCommandMap()`
+ Pre-existing baseline failures (~10 documented files: plugins, claude-pro
+ registration, moatBoot parallel-flake, ollama-real env probe). New tests
+ must not regress passing files.