# Contributor Map (Agent-Oriented)

This is a fast navigation guide for contributors (human or AI). It answers:

- Where do I add a new tool?
- Where do I add a new skill?
- Where do I change routing/policy?
- What tests should I run?

For the execution-flow diagram, see `docs/architecture/AGENT_DIAGRAM.md`.

## 30-Second Repo Tour

```text
src/
  daemon/        Start-up wiring, service init, message routing
  backends/      Native agent + orchestrator (tool loop lives here)
  tools/         Tool interfaces, policy, executor, builtins
  skills/        Skill loader/registry + install/watch infra
  hooks/         Confirm/log/silent policy + autonomy resolution
  sandbox/       Docker sandbox manager + sandboxed tool wrappers
  models/        Provider clients + model router + retry/cost/capabilities
  channels/      Chat adapters + pairing gate (Telegram/Discord/Slack/WhatsApp/Matrix/Signal/Mattermost/etc.)
  gateway/       WebSocket JSON-RPC server + web UI + handlers
  memory/        Hybrid search + embeddings + persistence
  session/       SQLite store + session mgmt
  cli/           CLI entrypoints + setup wizard
  automation/    Cron/webhooks/heartbeat/gmail watcher
docs/
  api/           Tool and gateway protocol docs
  security/      Capability model, sandboxing, injection resistance
  architecture/  Diagrams + contributor maps
config/
  default.yaml   Example configuration
```

## Adding a New Tool

### Where code goes

- Builtins live in `src/tools/builtin/`.
- Core types live in `src/tools/types.ts`.
- Tools are registered through the daemon wiring (see existing patterns in `src/daemon/index.ts`).

### Minimal tool skeleton

```ts
import type { Tool, ToolResult } from '../types.js';

export const myTool: Tool = {
  name: 'my.tool',
  description: 'What it does (model-facing).',
  // Optional: gate credentialed actions
  requiredSecretScopes: ['my_scope'],
  inputSchema: {
    type: 'object',
    properties: {
      foo: { type: 'string', description: '...' },
    },
    required: ['foo'],
  },
  execute: async (rawArgs: unknown, _context?: { signal?: AbortSignal }): Promise<ToolResult> => {
    // ...
    return { success: true, output: 'ok' };
  },
};
```

### Security checklist

- If the tool calls an external service or uses credentials:
  - set `requiredSecretScopes` on the tool.
  - ensure skill permissions can gate it (`manifest.json.permissions.secrets`).
- If it reads/writes files:
  - use `file.*` tools rather than bespoke FS access.
  - skills can restrict FS paths via `permissions.fs`.

### Tests to add

- Unit tests in `src/tools/builtin/<tool>.test.ts`.
- If you touch policy/executor logic: add tests in `src/tools/policy.test.ts` or `src/tools/executor.test.ts`.

## Adding a New Skill

### What a skill is

A skill is a package with:

- `SKILL.md`: instructions injected into the system prompt.
- `manifest.json`: metadata + capability declarations.

Where skills live:

- Bundled skills: `skills/`
- Managed skills (installed by Flynn): configured skill directory (see config)

Skill loading:

- Loader: `src/skills/loader.ts`
- Registry: `src/skills/registry.ts`
- Watcher (optional): `src/skills/watcher.ts`

### Capability permissions

If the skill is used via routing (intent target type `skill`), add `permissions` to `manifest.json`.

Without `permissions`, a skill is still loadable, but in skill context it has no tool access.

Reference: `docs/security/SAFE_PERSONAL_AGENT.md`.

## Routing: Agents vs Skills vs Default

Where routing decisions happen:

- Inbound routing: `src/daemon/routing.ts`

Inputs to routing:

- Channel + sender (agent router)
- Intent registry (regex rules) — can target `agent` or `skill`
- Metadata overrides (gateway / channel adapters)

If you need a new routing rule type:

- Intent targets live in the intent registry/types (see `src/intents/registry.ts`).

## Tool Policy + Execution

You will usually touch these files for capability/security work:

- Tool allowlisting: `src/tools/policy.ts`
- Tool runtime enforcement + audit: `src/tools/executor.ts`
- Confirmation/autonomy: `src/hooks/engine.ts`, `src/hooks/autonomy.ts`

In skill context:

- `ToolPolicyContext.skillName` and `.skillPermissions` are set in `src/daemon/routing.ts`.
- ToolPolicy filters available tools.
- ToolExecutor enforces fs/net/secret/injection restrictions even if a tool is somehow called.

## Sandbox

Sandbox components:

- Docker sandbox manager: `src/sandbox/manager.ts`
- Docker implementation: `src/sandbox/docker.ts`
- Sandboxed tool wrappers: `src/sandbox/tools.ts`
- Tool replacement wiring: `src/daemon/routing.ts`

Notes:

- Today the sandbox wiring replaces `shell.exec` and `process.start` when sandbox is enabled.
- In skill context, high-risk execution defaults to sandbox unless the skill opts into host execution.

## Gateway / API Surface

Gateway protocol docs:

- `docs/api/PROTOCOL.md`

Gateway handlers:

- `src/gateway/handlers/` (JSON-RPC methods)

Useful places to start:

- `src/gateway/server.ts` (server lifecycle)
- `src/gateway/protocol.ts` (types)

## Tests + Commands

Common checks:

```bash
pnpm typecheck
pnpm lint
pnpm test:run
```

Targeted tests for safety boundary changes:

- Tool policy: `pnpm test:run src/tools/policy.test.ts`
- Tool executor: `pnpm test:run src/tools/executor.test.ts`
- Skill loader: `pnpm test:run src/skills/loader.test.ts`
- Routing: `pnpm test:run src/daemon/routing.test.ts`

## First 3 PRs to Pick Up (Good Agent On-Ramps)

These are small, high-leverage changes that teach you the architecture quickly.

### PR 1: Add a new "narrow" skill + permissions

Goal: add a skill that can only do one bounded thing (example: summarize a URL).

Deliverables:

- `skills/url-summarizer/SKILL.md`
- `skills/url-summarizer/manifest.json` with permissions:
  - `tool_groups: ["group:web"]`
  - `net: [{"host":"*","ports":[443]}]` (or narrower if you prefer)
  - `execution_environment: "sandbox"` (default)

Acceptance:

- Skill loads (`flynn doctor` / skills list)
- In skill context, `shell.exec` is not available
- `web.fetch` works for https URLs

### PR 2: Route into the skill via intents

Goal: make it easy to invoke the skill without special UI.

Deliverables:

- Add an `intents.rules[]` entry targeting `type: skill`
  - Patterns like: `summarize *`, `tldr *`

Acceptance:

- A message like `summarize https://example.com` routes to the skill
- Tool list is capability-filtered for that skill context

### PR 3: Add an end-to-end safety test

Goal: lock in behavior so future refactors don’t weaken the boundary.

Deliverables:

- A test that asserts: when routed to a skill context with web-only permissions:
  - `ToolPolicy` excludes `shell.exec` and `file.write`
  - `ToolExecutor` denies a direct attempt to call `file.write` outside allowed fs globs

Suggested test locations:

- `src/tools/policy.test.ts`
- `src/tools/executor.test.ts`

## Where to Add What (Cheat Sheet)

```text
New tool .................. src/tools/builtin/ + register in daemon
Tool allow/deny logic ...... src/tools/policy.ts
Tool runtime enforcement .... src/tools/executor.ts
New skill .................. skills/<name>/{SKILL.md,manifest.json}
Skill loader/validation ..... src/skills/loader.ts
Skill routing (intents) ..... src/daemon/routing.ts + config intents
Sandbox behavior ........... src/sandbox/* + src/daemon/routing.ts
Confirmation UX ............ src/hooks/* + frontends/gateway
Web UI changes ............. src/gateway/ui/
```
