A TypeScript-based CLI coding agent built with OpenAI SDK and Ink.
flowchart TB
subgraph User["🖥️ User Terminal"]
UI["Ink React UI<br/>(index.tsx)"]
Input["Input Handler"]
Cmd["Slash Command<br/>Dispatcher"]
end
subgraph Agent["🤖 Agent Core (agent.ts)"]
Loop["Agent Loop<br/>think → act → observe"]
API["API Mode Router"]
RespAPI["Responses API<br/>(previous_response_id chain)"]
ChatAPI["Chat Completions API<br/>(local history)"]
Compactor["Context Compactor<br/>(compact.ts)"]
end
subgraph Tools["🔧 Tool Runtime (tools.ts)"]
Bash["bash"]
FileOps["read / write / edit"]
Search["glob / grep"]
WebFetch["web_fetch"]
TaskMgmt["task_* (CRUD)"]
TeamTools["teammate_* / message_send"]
McpEntry["mcp_call / list / read"]
SkillLoad["load_skill"]
end
subgraph Services["⚙️ Services & Managers"]
TaskMgr["TaskManager<br/>(.tasks/ JSON files)"]
MsgBus["MessageBus<br/>(.team/inbox/ JSONL)"]
TmMgr["TeammateManager<br/>(.team/config.json)"]
McpRuntime["MCP Runtime<br/>(mcp/)"]
SkillLoader["SkillLoader<br/>(skills/)"]
SubAgents["Sub-agents<br/>(subagents.ts)"]
end
subgraph Config["📋 Configuration"]
Settings["~/.weber/settings.json"]
Creds["~/.weber/credentials.json"]
Prompt["System Prompt Builder<br/>(prompt.ts)"]
end
subgraph External["🌐 External Systems"]
OpenAI["OpenAI API"]
McpServers["MCP Servers<br/>(stdio / HTTP)"]
Workspace["Workspace Files<br/>(AGENTS.md, skills/)"]
end
UI --> Input
Input --> Cmd
Cmd --> Loop
Loop --> API
API --> RespAPI
API --> ChatAPI
RespAPI --> OpenAI
ChatAPI --> OpenAI
Loop --> Tools
Loop --> Compactor
Tools --> Bash --> Workspace
Tools --> FileOps --> Workspace
Tools --> Search --> Workspace
Tools --> WebFetch --> External
Tools --> TaskMgmt --> TaskMgr
Tools --> TeamTools --> MsgBus
Tools --> TeamTools --> TmMgr
Tools --> McpEntry --> McpRuntime --> McpServers
Tools --> SkillLoad --> SkillLoader
Config --> Settings
Config --> Prompt --> Skills["Skills<br/>(global + local)<br/>AGENTS.md"]
Prompt --> Loop
TaskMgr --> Disk1["💾 .tasks/task_*.json"]
MsgBus --> Disk2["💾 .team/inbox/*.jsonl"]
TmMgr --> Disk3["💾 .team/config.json"]
weber (CLI binary)
│
├── src/index.tsx → Terminal UI (Ink/React), input loop, slash commands
├── src/agent.ts → Core agent orchestration, API routing, tool dispatch
├── src/tools.ts → 20+ tool schemas and handlers
├── src/config.ts → Settings loading, provider/model resolution
├── src/prompt.ts → System prompt composition (rules + skills + MCP + AGENTS.md)
├── src/compact.ts → Context compaction strategies
│
├── src/task-manager.ts → Persistent task DAG (JSON files)
├── src/message-bus.ts → Append-only inbox messaging (JSONL)
├── src/teammate-manager.ts → Teammate lifecycle, wake/sleep
├── src/subagents.ts → One-shot sub-agent spawner
│
├── src/mcp/
│ ├── client.ts → MCP transport client
│ ├── manager.ts → Connection lifecycle
│ ├── runtime.ts → Tool/resource/prompt bridge
│ └── types.ts → MCP protocol types
│
├── src/skills/
│ ├── index.ts → SkillLoader
│ ├── loader.ts → File discovery & parsing
│ ├── render.ts → Skill content rendering
│ ├── frontmatter.ts → YAML frontmatter parser
│ └── types.ts → Skill type definitions
│
├── src/oauth/
│ └── openai.ts → OpenAI OAuth flow
│
├── test/ → Test suite (node:test)
├── docs/ → Design notes & implementation docs
├── skills/ → Example local skills (pdf, code-review)
└── scripts/postinstall.mjs → Default config bootstrap
1. User types a prompt
│
2. index.tsx captures input & dispatches to agent.ts
│
3. agent.ts builds system prompt via prompt.ts:
• Built-in rules
• Loaded skill descriptions (global + local)
• MCP prompt instructions
• Project AGENTS.md (if present)
│
4. agent.ts sends [system + history + user message] to model
│
5. Model responds with text and/or tool calls
│
6. If tool calls:
• agent.ts routes to handler in tools.ts
• Handler executes (bash, file ops, MCP, etc.)
• Result fed back to model
• Repeat until model stops requesting tools
│
7. Final response streamed back to UI
🔒 ALL AGENTS (BASE_TOOLS)
├── bash → Shell commands (timeout 120s, dangerous command blocked)
├── read_file → Read workspace files
├── write_file → Write workspace files
├── edit_file → Exact-string replace in files
├── glob → File search (ripgrep)
├── grep → Content search (ripgrep)
├── web_fetch → Fetch web pages (HTML → plain text)
├── task_* → Task CRUD (create, update, list, get, complete, fail, block, assign)
├── list_mcp_resources / read_mcp_resource / mcp_call
└── load_skill → Load skill by name
🔒 LEAD ONLY (TOOLS = BASE + ...)
├── task → One-shot sub-agent dispatch
├── message_send → Send async message to teammate
├── teammate_spawn / teammate_list / teammate_shutdown
└── (lead inbox auto-injected per turn)
🔒 TEAMMATE (TEAMMATE_TOOLS = BASE + message_send)
└── message_send → Can send messages, but cannot spawn/delegate
- Workspace-scoped — All tools operate within
process.cwd(), file access is sandboxed - File-backed persistence — No databases; JSON and JSONL on disk for simplicity
- Explicit modules — One responsibility per file, direct composition over deep abstractions
- Defense in depth — Dangerous command filtering (16 patterns), shell timeout, output truncation (50KB)
- Skill override chain —
~/.weber/skills→~/.claude/skills→<workspace>/skills(last wins) - Teammate privilege reduction — Teammates get fewer tools than lead to prevent recursive delegation
---
## Generated on
2026-01-22
