sim-one-alpha

Capability System

The capability system lets users and agents add skills, tools, workers (subagents), and MCP servers to a running SIM-ONE Alpha instance without rebuilding.

Overview

Built-in Flue runtime capabilities are source-time application code. Built-in Agent Skills live under src/skills/<name>/SKILL.md, are imported with with { type: 'skill' }, and are registered directly on the owning agent or workflow. Example: src/skills/greeting-preflight/SKILL.md is registered on src/agents/orchestrator.ts.

The capability registry is the post-build extension lane. Its default paths are <runtime-root>/db/capabilities.sqlite and <runtime-root>/capabilities/. GOROMBO_CAPABILITY_DB_PATH and GOROMBO_CAPABILITIES_DIR can override them; relative overrides resolve under the same canonical runtime root. GOROMBO_CAPABILITY_DIR remains a supported fallback for the capability directory. The orchestrator reads the store at agent init (createAgent(...)) and merges user-defined capabilities into the same tools, skills, and subagents arrays that hold built-in capabilities. A service restart picks up changes; no rebuild is needed.

Four capability kinds:

Kind Flue ingress Runtime loading path
Skill skills: [...] + auto-discovery of <cwd>/.agents/skills/<name>/ Built-ins import from src/skills. Registry/user skills materialize into the discovery path. Flue loads both natively.
Tool tools: ToolDefinition[] Dynamic import() of user JS modules exporting defineTool(...) results.
Worker (subagent) subagents: AgentProfile[] Dynamic import() of user JS modules exporting defineAgentProfile(...) results.
MCP connectMcpServer(name, opts) -> { tools } connectMcpServer(...) per enabled row at init; tools spread into tools.

Architecture

User CLI request
-> sim-one command
-> applicable protocol bundle
-> shared lifecycle service
-> SQLite capabilities table
-> managed capability files

Agent lifecycle request
-> orchestrator and Protocol Tool
-> capability-manager
-> approval gate for mutations
-> shared lifecycle service
-> SQLite capabilities table
-> managed capability files

Capability implementation request
-> Coding Worker authoring skills and tools
-> protocol-routed classification, validation, scan, and tests
-> typed source handoff
-> capability-manager
-> Service restart
-> createAgent(...) init
-> loadUserCapabilities(env) reads SQLite
-> promoted managed packages are selected without refetching mutable sources
-> connectUserMcpServers() opens MCP connections
-> merge into tools/skills/subagents arrays
-> built-in + user capabilities live together

SQLite Schema

CREATE TABLE capabilities (
  id            TEXT NOT NULL,
  kind          TEXT NOT NULL,  -- 'skill' | 'tool' | 'worker' | 'mcp'
  name          TEXT NOT NULL,
  description   TEXT NOT NULL,
  source        TEXT NOT NULL,  -- 'github' | 'local' | 'npm' | 'builtin'
  source_ref    TEXT NOT NULL,  -- URL | workspace-relative path | built-in ref
  version       TEXT,
  enabled       INTEGER NOT NULL DEFAULT 0,
  config_json   TEXT NOT NULL DEFAULT '{}',
  installed_at  TEXT NOT NULL,
  updated_at    TEXT NOT NULL,
  installed_by  TEXT NOT NULL DEFAULT 'cli',
  PRIMARY KEY (kind, id)
);

CREATE INDEX IF NOT EXISTS idx_capabilities_kind_enabled
  ON capabilities(kind, enabled);

CREATE UNIQUE INDEX IF NOT EXISTS idx_capabilities_id_unique
  ON capabilities(id);

SQLite is authoritative. A config-file mirror (gorombo.config.json capabilities section) reconciles into SQLite on boot.

The persisted source enum retains builtin and the legacy npm value for registry compatibility. New lifecycle requests accept only github and local; unsupported sources fail before materialization. A github source must be a github.com HTTPS or SSH repository URL, so a local path or file:// URL cannot cross that trust boundary. Agent-installed local sources must be workspace-relative and resolve beneath <runtime-root>/workspace. Authenticated CLI callers may also provide an absolute local source path.

Product And Administration Surfaces

The sim-one binary is the authenticated user interface for capability management. Agent requests are delegated to the built-in capability-manager; the orchestrator has no direct capability mutation tools. A source checkout also includes scripts/capability-admin.mjs as a compatibility adapter to sim-one. It contains no SQLite or materialization implementation.

All three surfaces use CapabilityLifecycleService for list, inspect, validate, add, update, enable, disable, and remove. Agent mutations require a current matching approval. The capability manager accepts only the persisted normalized message eventId as protocol context, reloads the applicable bundle from the SQLite protocol provider, and rejects missing or mismatched event state. It does not trust a model-authored protocol bundle. Direct CLI commands are attributable to the authenticated user and do not accept model-supplied identity.

Enabled capability records are read when the orchestrator initializes. After a lifecycle change, restart the gateway through the process or service manager that launched it. See the CLI Reference for executable product commands.

Directory Layout

<configured-capability-directory>/
  skills/<id>/SKILL.md + supporting files
  tools/<id>/index.mjs
  workers/<id>/index.mjs

The default is <runtime-root>/capabilities/. GOROMBO_CAPABILITIES_DIR overrides it; relative overrides remain under the same canonical root. GOROMBO_CAPABILITY_DIR is the fallback override. Capabilities live outside the compiled server and survive upgrades.

Source Code

src/engine/capabilities/
  types.ts                 CapabilityRecord, CapabilityStore interfaces
  capability-lifecycle-service.ts
                           shared validation, mutation, rollback, and result contract
  capability-protocol-context.ts
                           fail-closed Protocol Tool bundle compiler
  capability-store.ts      SQLite CRUD
  capability-loader.ts     loadUserCapabilities(env) — reads SQLite, returns grouped by kind
  skill-materializer.ts    copies/github-clones sources into lifecycle staging directories
  mcp-broker.ts            connectUserMcpServers() — opens MCP connections, returns tools
  index.ts                 barrel exports

scripts/
  capability-admin.mjs     compatibility adapter to the sim-one CLI

src/engine/workers/
  capability-manager/      Flue lifecycle owner for agent requests
  coding-worker/
    capability-authoring/  scoped scaffold, validation, test, and handoff tools
    skills/                imported capability authoring skills

src/agents/
  orchestrator.ts          Modified — calls loadUserCapabilitiesFromStore(env) at init,
                            merges user tools/MCP into tools array, user workers into subagents

Reload At Initialization

Adding a capability writes to SQLite. When the gateway process restarts, createAgent(...) initialization re-reads SQLite and loads only the promoted managed package. It never recopies or reclones a mutable source during startup. An enabled record whose promoted package is missing fails closed and is not attached. No product rebuild is required. User-defined capabilities live in SQLite and <runtime-root>/capabilities/, outside the packaged application artifact.

Enablement And Approval

Agent-added skills may be enabled inside the approved add transaction because they contain instructions and supporting content rather than executable code. Agent-added tools, workers, and MCP connections are installed disabled and require a separate approved enable operation before they can enter the runtime. Updating an executable tool, worker, or MCP connection also returns it to the disabled state; the changed capability requires a separate enable operation. Direct CLI actions use the authenticated user as the principal.

After enablement, executable capabilities remain subject to protocols, trusted scope, owning-agent attachment, sandbox policy, and action-specific approval requirements.

Protocol-Routed Validation

The capabilities.lifecycle-routing base protocol governs capability work. Coding Worker classification, source validation, security scanning, tests, packaging, and handoff require the applicable Protocol Tool bundle. Capability-manager validation and every mutation require it as well.

These paths fail closed when the bundle is missing or malformed. Successful validation and handoff results include redacted protocol context with applied protocol ids and rules. Deterministic checks do not replace protocols; they run after protocol directives have been compiled. Source-backed validation uses a non-executing TypeScript syntax check for exported Flue factories and a shared package scan for credential values and machine-specific absolute paths.

Coding Worker Authoring

The Coding Worker owns source development inside the selected workspace/projects/<slug> or workspace/repos/<slug> target. It imports Flue skills for capability design, skill authoring, tool authoring, worker authoring, and MCP authoring. Its typed tools classify, approval-gate scaffolding, validate contracts, scan for secrets and machine host paths, run bounded tests, and prepare a content-digest-bound handoff.

A handoff requires passing test evidence for the current content digest and protocol directives. Local approval metadata includes a SHA-256 source identity instead of the private path itself, so an approval cannot be reused for a different local source. Staging rejects symbolic links and verifies sha256:<digest> handoffs against the exact materialized package before promotion. Add and update approvals also include a canonical digest of the complete lifecycle mutation payload, so changed names, descriptions, sources, versions, activation requests, or MCP settings require a distinct approval. Executable source files containing NUL bytes or invalid UTF-8 fail validation instead of being skipped as binary package assets.

MCP connection handoffs carry the validated endpoint, transport, and optional canonical token configuration key. Supported token slots are GOROMBO_MCP_TOKEN, MCP_AUTH_TOKEN, and MCP_TOKEN; lifecycle validation rejects any other key before the record can be enabled. Partial MCP updates merge defined fields with the stored connection before validation, so changing transport or token configuration does not discard the endpoint.

Executable package validation accepts only direct exported defineTool(...) or defineAgentProfile(...) results, including arrays made entirely from direct results. A function that merely contains a factory call is not a loadable Flue capability and is rejected before promotion.

The Coding Worker never imports the capability store, lifecycle service, materializer, or managed capability path resolver.

Config-File Mirror

gorombo.config.json has a capabilities array that reconciles into SQLite on boot (in src/db.ts, at server startup — before any agent request). Config is additive: entries in config but missing from SQLite get inserted with installedBy: "seed"; entries already in SQLite are skipped (idempotent). Reconciliation does not fetch or copy source bytes at startup; an enabled source-backed record is attached only when its promoted managed package already exists. Removal is a CLI/db operation, not a config edit.

{
  "version": 1,
  "models": { "primary": "..." },
  "capabilities": [
    {
      "id": "my-skill",
      "kind": "skill",
      "name": "My Skill",
      "description": "...",
      "source": "github",
      "sourceRef": "https://github.com/user/my-skill",
      "enabled": true
    }
  ]
}