Design Decisions

March 18, 2026 · View on GitHub

Core

DecisionChoiceRationale
StandaloneReads format directlyIndependence, simpler install, no coupling
Tools discovered at runtimeAgent adapts to harnessPortable definitions, no dep declarations
In-process MCP serversOne server per tool domainNo external processes, fast, simple
Config-driven tool enable/disableconfig.yaml controls what's availableUser controls their environment
tsx as runtimeNo build step for JSXSimpler than bundling React/Ink
~/.mastersof-ai/ home dirGlobal config + agents + stateStandard Unix convention
Memory as a toolNot baked into coreJust another context source
Sub-agents as .md files (planned)Same format as primary agentsUniform, composable, portable
Bubblewrap sandboxOptional --sandbox flagIsolate agent filesystem access without Docker overhead

Dual-Interface Architecture

DecisionChoiceRationale
Two interfaces, one runtimeTUI + Web UI share agent coreNo code duplication; agent behavior is identical regardless of interface
Fastify for serve modeNot Express (which is used only for A2A)Typed, fast, native WebSocket + CORS support, async-first
WebSocket for streamingNot SSE or pollingBidirectional (interrupts, tool approvals), lower overhead, message replay on reconnect
Separate frontend SPAweb/ dir, Vite + React, deploys independentlyFrontend on CDN (Cloudflare Pages), backend on VPS — decoupled scaling
Token auth via access.yamlSHA-256 hashed tokens, constant-time comparisonSimple, no external auth service, hot-reloadable, secure at rest
Per-user session isolationSessions stored under sessions/{user}/No cross-user data leakage, supports per-user cost caps
Default port 3200 for serveNot 3000 (common conflict)Avoids collision with Vite dev server and other common services

Agent Definition

DecisionChoiceRationale
YAML frontmatter in IDENTITY.mdOptional metadata block, identity content untouchedAgent definition stays human-readable; structured data for tooling
Agent Card from IDENTITY.mdParse H2 sections as skillsNo separate card file to maintain — identity is the source of truth
Per-agent tool filteringtools.allow / tools.deny in frontmatterAgent authors control capabilities; enforced at server creation time
Per-agent MCP serversmcp field in frontmatter with URI or commandAgents can bring external tools without global config changes

Agent Behavior

DecisionChoiceRationale
Sub-agent scratchpadDedicated .scratch/ tool, not workspaceScoped access, path confinement, clear separation from workspace files
Verification hookSystem prompt + canUseTool trackingDual approach — prompt sets expectations, hook enforces verify-after-write
Loop detectioncanUseTool edit counterLightweight, resets on verification, configurable threshold
Compact success outputPostToolUse hook truncationKeeps context clean — failures stay verbose, successes get summarized

A2A Protocol

DecisionChoiceRationale
A2A server as separate moduleExpress in src/a2a/, not merged into Fastify serveA2A is a standard protocol with its own SDK; serve mode is a custom web backend
A2A client as MCP toola2a_discover / a2a_call / a2a_listAgents call external agents the same way they use any tool — discoverable at runtime

Production (Serve Mode)

DecisionChoiceRationale
Cost caps per userRolling window budgets (session, daily, monthly)Prevents runaway costs; budget exceeded = blocked until window resets
Hot reloadFile watcher on agents dir, config, access.yamlNo server restart needed for agent changes or access revocation
Graceful shutdown30s drain timeout, then force closeActive conversations complete cleanly; state is persisted before exit
LGPD complianceData export, deletion, consent tracking, retention cleanupRequired for Brazilian users; built into serve mode from the start