A pnpm monorepo. Packages depend inward toward core; nothing in core depends on a
provider, transport, or UI.
cli ─┬─ tui ──┬─ core
│ ├─ secrets
│ ├─ workflows ── core
│ └─ graph ────── core
├─ providers ── core
├─ router ──── providers, core
├─ tools ───── core
├─ plugins ─── core, skills
├─ lsp ─────── core
├─ sandbox ─── core
├─ secrets
└─ server ──── router, tools, core
The provider-blind heart. No external deps.
types.ts— canonical types:CanonicalMessage,ContentPart,CanonicalEvent,StopReason,ToolSpec,Capabilities,GenerateRequest,Provider.permissions.ts—PermissionEngine+PermissionMode(plan/ask/acceptEdits/yolo).agent.ts—Agent(the loop) emittingAgentUIEvents.hooks.ts— lifecycle hook runner (PreToolUsedeny,$TOOL_NAME/$FILE/$PROMPT, …).memory.ts— curated.polycode/memory.mdread/append/replace.images.ts—@file.png→ImagePart(base64).
ai-sdk-provider.ts—createAiSdkProvider(): the only AI-SDK-aware code. Maps canonical ⇄ AI SDK (fullStream,ModelMessage,ToolSet), plusreasoningOptions()per provider.index.ts—makeProvider({provider, model}),parseModelArg("provider:model"), per-providerCapabilities. Deps:ai,@ai-sdk/openai,@ai-sdk/google,@ai-sdk/xai.
classify(text, contextTokens)→cheap | strong | long.Routerbuilds + memoizes aProviderper tier fromRouterConfig.
The default tool registry (tools), each a ToolSpec with a permission class:
| Tool | Class | Notes |
|---|---|---|
read |
safe | UTF-8 file read, path-jailed to the project root |
write |
mutating | create/overwrite a file |
edit |
mutating | exact-string replace (errors if absent) |
bash |
dangerous | shell command with timeout |
grep |
safe | regex over file contents |
glob |
safe | simple */** file matching; first line is the match count |
task / task_wait / task_kill |
mutating | parent-only child spawn / wait / kill |
graph |
mutating | parent-only named graph run (checkpointed) |
memory |
mutating | curated .polycode/memory.md (read/append/replace) |
Tool-execution backends implementing core's Sandbox: LocalSandbox (host shell,
path-jailed) and DockerSandbox (shell in a locked-down container, file ops on the
bind-mount). createSandbox({ kind, root, ... }). See Security & Keys.
ToolContext carries a Sandbox, so tools do no direct fs/child_process.
addGitWorktree / applyGitWorktree / listGitWorktrees / removeGitWorktree
manage detached trees under .polycode/worktrees/.
Secure key store: getKey / setKey / deleteKey / configured / hydrateEnv /
backendName / storeLocation. Optional dep @napi-rs/keyring (keychain); 0600 file
fallback. See Security & Keys.
Claude-Code-style Ink UI. Root orchestrates Settings vs. the app; Settings handles keys
(masked paste · env import · open key page · validate · agentic hook); App is the chat loop
(welcome Banner, ⏺/⎿ tool rendering, Markdown assistant output, bordered composer,
spinner with elapsed + esc-to-interrupt, $token status line, slash commands); theme.ts holds the
accent/glyph palette. Deps: ink, ink-text-input, ink-spinner, react,
@polycode/core, @polycode/secrets.
Budgeted TypeScript runner: runParallel / runSequential / runWorkflowFile
plus JSON loaders (loadWorkflows). Host is spawnChild. Not Rhai.
LangGraph-shaped state machine on the existing loop: JSON graphs, reducers, conditional
edges, file checkpointer (.polycode/graph-runs/). Nodes are spawnChild agents. Not
@langchain/langgraph. See graph.md.
loadPlugins(cwd) reads .polycode/plugins/<name>/ and user plugins. A bundle can ship
skills, slash commands, extra task agents, hooks, MCP servers, and LSP server configs.
JSON-RPC stdio client + createLspTool. Registered only when .polycode/lsp.json or a
plugin lsp.json lists a server. Host-side (not docker-jailed).
startServer() — Node http server exposing the same engine over POST /chat (SSE) and
GET /health. Bearer / X-Api-Key, hosted permission policy, rate limits, body caps,
audit JSONL, IDE bridge (/ide/*). Deps: @polycode/{core,router,tools}.
Entry point: parse flags, load config, hydrateEnv(), then either startTui(...) or
startServer(...). bin: poly (after build).
- Root scripts:
dev,serve,smoke,typecheck,docs,build. - Dev deps:
tsx(run TS directly),typescript,tsup(bundle),marked(docs HTML). - Dev packages use
main/exports→src/index.tssotsxresolves source directly.