agent-system
Grida AI agent system work: `@grida/daemon` (DaemonServer, loopback HTTP perimeter, files/workspaces, secrets store, daemon discovery) and `@grida/agent` (the agent tenant: sessions, providers/BYOK, runtime/tool execution, skills discovery, prompts, tiers, sandbox hosts). Use for `packages/grida-daemon/**`, `packages/grida-ai-agent/**`, desktop sidecar protocol changes, agent chat transport, and bugs in agent state or streams. For pure Electron window, preload, menu, deep-link, or CDP work, use `desktop`.
适合你,如果你在开发或维护 Grida AI agent 系统
npx oh-my-skill add gridaco/grida/agent-systemcurl -fsSL https://oh-my-skill.com/install.sh | bash -s -- gridaco/grida/agent-systemnpx oh-my-skill verify gridaco/grida/agent-system怎么用
技能原文 SKILL.md
Grida Agent System
This skill is for the two packages behind Grida Desktop and future hosts (issue #927): @grida/daemon — the local host layer (DaemonServer lifecycle, the loopback HTTP perimeter, files/recents/workspaces, the secrets store, daemon discovery, the tenant seam) — and @grida/agent — the agent TENANT mounted on it (sessions, providers, tool execution, prompt composition, skills, the AI-SDK stream contract). Dependency direction is one-way: @grida/agent imports @grida/daemon; the daemon is AI-free by contract (pinned by packages/grida-daemon/src/__boundary__.test.ts).
Use [desktop](../desktop/SKILL.md) for Electron shell work: BrowserWindow, menus, preload, native dialogs, file associations, deep links, and CDP verification.
Adjacent: [sdk-design](../sdk-design/SKILL.md) and [sdk-seam](../sdk-seam/SKILL.md) for exported contracts and host seams, [security](../security/SKILL.md) when a change touches a GRIDA-SEC boundary.
When to use this skill
- Editing
packages/grida-daemon/**orpackages/grida-ai-agent/**. - Changing DaemonServer lifecycle, the tenant seam, server capabilities, HTTP routes, transport, Basic Auth, Referer policy, sessions, workspaces/files, recents, secrets, BYOK providers, model tiers, sandbox policy, shell policy, runtime, tools, prompts, skills, or message streams.
- Touching the desktop sidecar protocol because the daemon contract changed.
- Debugging empty file lists, missing sessions, broken stream parts, provider resolution, tool-call behavior, or agent state recovery.
- Editing renderer agent chat transport when the bug is in stream/session semantics rather than Electron bridge presence.
Skip this skill for BrowserWindow, menu, native dialog, file association, deep-link, packaging, or preload-only bugs. Use desktop for those.
Shape
Host adapter (Desktop today, other hosts later)
- supplies auth material, workspace roots, entitlement hooks, sandbox wrapper
- starts the composed daemon (createAgentDaemon) as sidecar or CLI daemon
|
v
DaemonServer (@grida/daemon/server)
- loopback Hono perimeter (CORS -> Referer -> Basic Auth)
- host capability routes: files, recents, workspaces + secrets store
- the DaemonTenant seam (static typed list, not a plugin registry)
|
v
Agent tenant (@grida/agent/server — createAgentTenant)
- AI route groups: /agent, /events, /sessions, /secrets, /providers,
/images, /video
- sessions SQLite, endpoint configs, runtime + run loop, stream registry
|
v
Runtime-agnostic agent core (@grida/agent)
- protocol DTOs, prompts, tiers, skills, toolset, AI-SDK UI-message stream
The host owns process supervision and native capability exposure. The daemon package owns the perimeter and host capabilities; the agent package owns agent-system semantics.
Package Boundaries
Two packages, each with intentional entrypoints.
@grida/daemon (the host layer — AI-free by contract):
@grida/daemon: handshake vocabulary (DaemonCapabilities,DAEMON_PROTOCOL), local-resource DTOs.@grida/daemon/server: Node-onlyDaemonServer,buildServer, theDaemonTenant/DaemonServicesseam,Daemondiscovery, and the tenant toolkit (WorkspaceRegistry, workspaceFs, SecretsStore, shell runner, request validation).@grida/daemon/transport: Basic Auth signing, fetch/SSE helpers, andDaemonTransport.Client(daemon route groups).@grida/daemon/sandbox: the sandbox policy frame (buildDaemonSandboxPolicy).
@grida/agent (the agent tenant — depends on @grida/daemon):
@grida/agent: neutral contracts, provider metadata, run/stream DTOs,createAgent, prompt composition, toolset, tiers, and session row types.@grida/agent/server: Node-onlycreateAgentTenant+createAgentDaemon(the composed server hosts run).@grida/agent/transport:AgentTransport.ClientextendsDaemonTransport.Clientwith the tenant routes (sessions, run/stream, events, secrets, providers, images, video).@grida/agent/sandbox: composed policy (buildAgentDaemonSandboxPolicy— daemon frame + AI upstream hosts).@grida/agent/fs: storage-agnostic virtual filesystem and AI-SDK file tools.@grida/agent/fs/backends/opfs: browser OPFS backend.@grida/agent/todos: plan store andtodo_write.@grida/agent/tiers: model tier constants.
Keep browser-safe imports neutral. Node-only code must stay behind server, sandbox, or host adapter entrypoints. Never add an AI import to @grida/daemon — the boundary test fails, and the change belongs in the tenant. A non-AI host capability (a new file route, a viewer backend) belongs in @grida/daemon, never here.
Do not create a second desktop-specific agent implementation under desktop/src/**. Desktop supervises and adapts the composed daemon; it does not own the agent semantics.
Ownership Rules
Core tests belong in the owning package first. Perimeter, files, workspaces, secrets-store, and seam bugs get tests under packages/grida-daemon/src/**/*.test.ts; session, provider, runtime, tool, and stream-formatting bugs under packages/grida-ai-agent/src/**/*.test.ts.
Desktop tests should prove Electron imports, starts, and wires the core. They should not duplicate daemon or tenant behavior.
Anti-goals to preserve:
- Not a general model-provider router.
- Not a hosted model gateway.
- Not a billing or entitlement engine.
- Not a multi-agent orchestration graph.
- Not a UI framework.
- Not a desktop bridge package.
- Not a private chat-history IR; session rows are the contract.
Common Diagnostics
Empty list_files in a workspace-bound agent usually means the workspace filesystem was not hydrated. For design-agent workspace runs, @grida/agent must create AgentFs(NodeFsBackend(root)) and call await fs.hydrate() before tool calls.
An agent that sees SOME files but is missing whole subtrees (a .canvas deck, or most of the repo) is almost always hydrate-scan truncation, not a bug in those files. The walk stops at SCAN_MAX_FILES (10k) / SCAN_MAX_DEPTH and warns [agent-fs] … hydrate scan hit a cap … truncated (sidecar stderr). The usual cause is a large workspace_root containing heavy dirs that are NOT in IGNORED_SCAN_DIRS — vendored toolchains / git submodules (e.g. emsdk) or .claude/worktrees (full repo copies). .gitignore is NOT consulted, so a submodule slips through. Fixes: scope the workspace to the real project subdir, or add the offender to IGNORED_SCAN_DIRS in @grida/daemon's workspaces/scan.ts.
A client-resolved tool call that hangs at input-available (the turn just ends with no result; the assistant never continues) is the server-authoritative model view dropping it. The runtime rebuilds the model's input from the PERSISTED messages (buildModelMessages over listVisibleMessages), NOT the client's array — and it drops any tool call without a terminal result. For a workspace-less session (the desktop file-window sidebar, which resolves fs tools in the renderer over the live editor), the result lives only on the client's next-request assistant message. persistIncomingTail must persist those terminal tool-result parts (it does, as of the file-window sidebar fix) or the call stays input-available forever and the model never sees the answer. Diagnostic tell: workspace sessions show tool_state=output-available parts in sessions.db; a no-workspace session stuck at input-available for EVERY tool call is this class, not a tool bug. (Server-resolved tools are unaffected — the recorder writes their result straight from the stream.)
Broken desktop agent calls can still be package bugs. Check whether the same operation fails through AgentTransport.Client or package tests before debugging Electron.
If a method needs secrets, keep secret reads inside the daemon process (the store is @grida/daemon's SecretsStore; the /secrets routes are tenant-registered). The renderer may check presence and set/delete BYOK keys, but it must not receive raw secret values.
If a change adds host-specific behavior, define the strict host capability contract first. Do not let Node, Electron, or renderer-only imports leak into neutral package entrypoints.
Live state on disk (inspecting a real session)
You CAN inspect a real running session — the host persists agent state under ~/.grida/agent/, separate from Electron's userData (the desktop supervisor passes it to the sidecar as --user-data; see home.join("agent") in desktop/src/main/agent-sidecar-supervisor.ts):
sessions.db— SQLite (WAL):chat_sessions(incl.workspace_root,mode,parent_id),chat_messages,chat_parts. Schema insrc/session/schema.ts.workspaces.json— the workspace registry (id → root).auth.json,recent.json.
Read it read-only (don't perturb the live WAL). The first thing to check for "why can't the agent see X" is workspace_root — the agent only sees files under it (and only up to the hydrate cap, above):
sqlite3 "file:$HOME/.grida/agent/sessions.db?mode=ro" \ "SELECT id, workspace_root, mode FROM chat_sessions WHERE id='ses_…';"
Security Boundary
The daemon's HTTP perimeter (@grida/daemon) is one layer of GRIDA-SEC-004 when hosted by Desktop:
- Per-launch Basic Auth credentials are supplied by the host adapter.
- The preload signs requests; credentials stay in closure, not on
window.grida. - The daemon checks auth on every request — tenant routes included.
- Referer checks defend against same-origin XSS reaching the loopback server.
- Secrets APIs expose presence/set/delete semantics, not raw secret reads.
- The
auth_tokenquery carriage is exactly the GET SSE routes the agent tenant declares viasse_query_token_paths— never widened.
If a route can mutate local files, start processes, read secrets, or execute tools, review both the transport contract and the host capability that grants it.
Verification
For package changes (run the pair for the package(s) you touched):
pnpm --filter @grida/daemon typecheck && pnpm --filter @grida/daemon test pnpm --filter @grida/daemon build pnpm --filter @grida/daemon test:browser # perimeter system harness (Chromium) pnpm --filter @grida/agent typecheck && pnpm --filter @grida/agent test pnpm --filter @grida/agent build
A change to @grida/daemon requires rebuilding it before @grida/agent typechecks (the tenant compiles against the daemon's dist).
For session-store smoke checks against a real SQLite file:
pnpm --filter @grida/agent smoke:sessions:live
If the change crosses into Desktop sidecar wiring, also run the Electron owner checks from the desktop skill.
Pointers
Daemon (packages/grida-daemon/):
- Package overview:
packages/grida-daemon/README.md - DaemonServer:
packages/grida-daemon/src/daemon-server.ts - HTTP frame + seam + daemon routes:
packages/grida-daemon/src/http/(server.tsholdsDaemonServices/DaemonTenant) - Daemon transport:
packages/grida-daemon/src/transport.ts - Discovery:
packages/grida-daemon/src/daemon.ts - Workspaces/files:
packages/grida-daemon/src/workspaces.ts,packages/grida-daemon/src/files/ - Hydrate-scan policy (ignored dirs + caps):
packages/grida-daemon/src/workspaces/scan.ts - Secrets store + shell runner:
packages/grida-daemon/src/secrets.ts,packages/grida-daemon/src/shell/ - AI-free boundary pin:
packages/grida-daemon/src/__boundary__.test.ts
Agent tenant (packages/grida-ai-agent/):
- Package overview:
packages/grida-ai-agent/README.md - Tenant + composed daemon:
packages/grida-ai-agent/src/server.ts - Agent routes:
packages/grida-ai-agent/src/http/routes/ - Agent transport:
packages/grida-ai-agent/src/transport.ts - Runtime:
packages/grida-ai-agent/src/runtime/ - Sessions:
packages/grida-ai-agent/src/session/ - Virtual fs tools:
packages/grida-ai-agent/src/fs/ - Live on-disk state (real sessions/workspaces):
~/.grida/agent/(sessions.db,workspaces.json) — see "Live state on disk" above - Providers:
packages/grida-ai-agent/src/providers/ - Skills/prompts/tools:
packages/grida-ai-agent/src/skills/,packages/grida-ai-agent/src/agent/,packages/grida-ai-agent/src/tools/ - Tool-design doctrine (read before adding/widening a tool — minimal surface, host-config off the args, grounded/honest knobs, auto-resolved inputs, context economy, clear typed failures, tool-vs-connector-vs-skill):
docs/wg/ai/agent/tool-design.md; in-code checklist is theTOOL-DESIGNblock insrc/tools/index.ts - Desktop sidecar adapter:
desktop/src/agent-sidecar.ts - Renderer agent chat transport:
editor/lib/agent-chat/