# Code map

This page helps you find where your change goes, and follow the conventions already there.

This is the contributor-facing counterpart to the [maintainer documentation](./index.md): where
the code lives and how it's wired, rather than what the harness does at runtime.

---

## Core Principles

Jazz is a Bun workspace under `packages/*`. The dependency rule below is not just documented
convention: it's structurally enforced by TypeScript project references, so `tsc -b` rejects a
package importing from one it doesn't declare a reference to.

- **`packages/core/`** contains the domain, contracts (interfaces and types), and business logic.
  - No imports from `packages/adapters/` or `packages/cli/` allowed in core, except in tests.
  - Contracts are expressed as interfaces + Context tags (e.g., `AgentConfigServiceTag`).
  - Publishable standalone as `@jazz/core`: no workspace dependencies of its own.
- **`packages/plugin-sdk/`** is the zero-runtime-dependency public TypeScript contract for plugin
  authors. Core structurally implements that plain-JavaScript ABI without exposing Effect values.
- **`packages/adapters/`** implements adapters for model providers, configuration, storage,
  files, MCP, telemetry, notifications, peers, and webhooks, plus the goal and loop cycle
  runners and run-ownership primitives that the CLI and the daemon both use.
  - Adapters provide Layers that satisfy the tags declared in `core/interfaces`.
  - Depends on `core` only.
- **`packages/daemon/`** is the daemon application: the authenticated HTTP server, the
  trigger/goal/loop/job ticks, attention gating, and OS service install.
  - Depends on `core` and `adapters`; nothing below it imports it (an eslint rule and
    `scripts/package-layering.test.ts` enforce that).
- **`packages/cli/`** contains user-facing command implementations, Ink/OpenTUI presentation,
  and the terminal-rendering `TerminalService` implementation.
  - Depends on `core`, `adapters`, `daemon`, `bot-shared`, and the bridge packages it launches.
- **`packages/runtime/`** is the composition root: wires core, adapters, and cli into the
  Effect Layer graph that becomes the `jazz` binary.
  - Depends on `core`, `adapters`, and `cli`.
- **`packages/bot-shared/`**, **`packages/telegram-bot/`**, **`packages/discord-bot/`**,
  **`packages/whatsapp-bot/`**, **`packages/imessage-bot/`**, and **`packages/photon-bot/`** are the
  chat-bridge integrations. `bot-shared` holds the turn, approval, and sandbox helpers the bridges
  share.
- **`packages/website/`** is the Astro site that serves the public docs, the marketplace library,
  and the plugin catalog.

## The dependency rule

```mermaid
flowchart TB
    CLI["<b>packages/cli/</b><br/>commands · Ink TUI · presentation · TerminalService"]
    CORE["<b>packages/core/</b><br/>agent loop · tools · context · types<br/><b>interfaces = ports</b><br/><i>imports nothing outward</i>"]
    ADP["<b>packages/adapters/</b><br/>llm · storage · mcp · history<br/>logger · telemetry · notification"]
    DMN["<b>packages/daemon/</b><br/>HTTP server · ticks · attention · service install"]
    RT["<b>packages/runtime/</b><br/>composition root · jazz binary"]

    CLI -->|"calls"| CORE
    ADP -->|"implements ports"| CORE
    DMN -->|"runs on"| ADP
    CLI -->|"jazz daemon"| DMN
    RT -.->|"merges Layers at startup"| CLI
    RT -.->|"merges Layers at startup"| ADP
    RT -.->|"merges Layers at startup"| CORE

    NO["core/ → adapters/ or cli/<br/><b>never</b> (except in tests)<br/>adapters/ → daemon/ <b>never</b>"]

    classDef core fill:#4f9d9d,stroke:#2f6d6d,color:#ffffff
    classDef forbidden fill:#c1443c,stroke:#7d2b26,color:#ffffff
    class CORE core
    class NO forbidden
```

Arrows point inward, always. That's what lets you swap a storage backend or add an LLM
provider by touching one package, and test the agent loop with plain mocks.

Adding a capability follows the arrows in reverse:

```mermaid
flowchart LR
    A["1 · Define the port<br/>packages/core/src/interfaces/foo.ts<br/>interface + Context.GenericTag"]
    B["2 · Implement the adapter<br/>packages/adapters/src/foo.ts<br/>+ a Layer"]
    C["3 · Register the Layer<br/>packages/runtime/src/app-layer.ts"]
    D["4 · Test with a mock Layer<br/>Layer.succeed(FooTag, fake)"]
    A --> B --> C --> D

    classDef step fill:#4f9d9d,stroke:#2f6d6d,color:#ffffff
    class A,B,C,D step
```

---

## Directory Structure

```text
packages/
├── cli/src/                      # @jazz/cli: user-facing CLI
│   ├── commands/                 # Command entry points and orchestration
│   ├── setup/                    # Shared interactive provider/search configuration flows
│   ├── helpers/                  # Narrow detection, parsing and formatting operations
│   ├── presentation/             # Output formatting (markdown, CLI renderer)
│   ├── chat-service.ts           # Chat orchestrator (UI-touching; lives here, not adapters)
│   ├── chat/                     # Chat service modules
│   │   ├── commands/             # Slash command handling
│   │   │   ├── parser.ts         # Parse /help, /new, etc.
│   │   │   ├── handler.ts        # Route commands and apply shared command behavior
│   │   │   └── conversation.ts   # Start, fork, resume and rename conversations
│   │   └── session/              # Session management
│   │       ├── manager.ts        # ID generation, logging
│   │       └── agent-setup.ts    # MCP connection setup
│   ├── terminal.ts               # TerminalService implementation (Ink/OpenTUI rendering)
│   └── ui/                       # Ink React components
│       ├── App.tsx               # Main app with store pattern
│       ├── ErrorBoundary.tsx     # Error boundary for graceful failures
│       ├── LineInput.tsx         # Readline-style input component
│       └── text-utils.ts         # Word boundary utilities
│
├── core/src/                     # @jazz/core: domain and contracts
│   ├── agent/                    # Agent execution engine
│   │   ├── agent-runner.ts       # Orchestrator (delegates to executors)
│   │   ├── types.ts              # Shared types (AgentRunnerOptions, etc.)
│   │   ├── context/              # Context management
│   │   │   └── summarizer.ts     # Auto-summarization for context window
│   │   ├── execution/            # LLM execution strategies
│   │   │   ├── streaming-executor.ts  # Real-time streaming
│   │   │   └── batch-executor.ts      # Non-streaming execution
│   │   ├── prompts/              # System prompts by agent type
│   │   └── tools/                # Tool implementations
│   │       ├── fs/               # Filesystem tools (read, write, grep, etc.)
│   │       ├── command-risk.ts   # execute_command risk classifier (LLM)
│   │       ├── tool-categories.ts # Builtin category ids + mappings
│   │       ├── register-tools.ts # Builtin tool registration
│   │       └── register-mcp-tools.ts # Per-agent MCP connect + register
│   ├── interfaces/               # Service contracts (Tag + Interface)
│   ├── types/                    # Domain types
│   └── utils/                    # Shared utilities
│
├── adapters/src/                 # @jazz/adapters: adapter implementations
│   ├── llm/                      # LLM provider adapters
│   ├── mcp/                      # MCP client + OAuth
│   ├── peers/                    # ask_peer ledger/token adapters
│   ├── goals/, loops/            # Goal/loop actions and cycle runners
│   ├── runs/                     # Run ownership: in-flight set, resume-owned-run
│   └── storage/                  # Persistence (JSON file storage)
│
├── daemon/src/                   # @jazz/daemon: HTTP server, ticks, attention, service install
│
├── runtime/src/                  # @jazz/runtime: composition root
│   ├── entry.ts                  # Binary entrypoint
│   ├── cli-app.ts                # Commander.js program, command registration
│   └── app-layer.ts              # Effect Layer composition
│
├── bot-shared/src/                # @jazz/bot-shared: shared bridge helpers
├── telegram-bot/src/              # Telegram bridge
├── discord-bot/src/               # Discord bridge
├── whatsapp-bot/src/              # WhatsApp bridge (linked device, Baileys)
├── imessage-bot/src/              # iMessage bridge (local Mac, imsg CLI)
├── photon-bot/src/                # iMessage bridge (hosted Photon line)
└── website/                       # Astro site: docs, marketplace library, plugin catalog
```

---

## Key modules

### Agent Runner (`packages/core/src/agent/`)

The agent runner is split into focused modules; runtime behavior is documented in
[Agent loop](./run-lifecycle.md) and [Context management](./context-lifecycle.md).

| Module                            | Purpose                                                                |
| --------------------------------- | ---------------------------------------------------------------------- |
| `agent-runner.ts`                 | Orchestrator - delegates to executors                                  |
| `types.ts`                        | Shared types: `AgentRunnerOptions`, `AgentResponse`, `AgentRunContext` |
| `context/summarizer.ts`           | Auto-compaction when context approaches token limit                    |
| `execution/streaming-executor.ts` | Real-time LLM streaming with tool calls                                |
| `execution/batch-executor.ts`     | Non-streaming execution with retry logic                               |

**Dependency Injection Pattern**: To avoid circular dependencies, the `summarizer.ts` accepts a `RecursiveRunner` function parameter instead of importing `AgentRunner` directly.

#### Prompt assembly

`AgentPromptBuilder` assembles system prompts through three semantic layers:

- **Core** contains the persona and fixed Jazz harness guidance.
- **Scope** contains instructions belonging to the current project or task.
- **Live** contains runtime facts that may change while the agent runs, such as its environment.

`prompts/layers.ts` owns their `Core → Scope → Live` rendering order. Keep new prompt content in
the narrowest-lived layer that accurately describes it. Tool-specific operating details belong in
the tool description rather than any shared layer.

### Chat Service (`packages/cli/src/chat/`)

The chat service is split into focused modules:

| Module                     | Purpose                                      |
| -------------------------- | -------------------------------------------- |
| `chat-service.ts`          | Session orchestrator                         |
| `commands/parser.ts`       | Parse slash commands from user input         |
| `commands/handler.ts`      | Route commands and shared command behavior   |
| `commands/conversation.ts` | Start, fork, resume and rename conversations |
| `commands/types.ts`        | `SpecialCommand`, `CommandResult` types      |
| `session/manager.ts`       | Session ID generation, logging               |
| `session/agent-setup.ts`   | MCP server connections before chat           |

---

## Common Conventions

### Service Contracts

A service contract is an interface + a Context tag, defined under `packages/core/src/interfaces/`.

```typescript
// packages/core/src/interfaces/agent-config.ts
export interface AgentConfigService {
  getConfig(): Effect.Effect<AgentConfig, Error>;
}

export const AgentConfigServiceTag = Context.GenericTag<AgentConfigService>("AgentConfigService");
```

### Using Services in Effect

```typescript
const config = yield * AgentConfigServiceTag;
const value = yield * config.getConfig();
```

### Providing Layers

```typescript
Layer.effect(AgentConfigServiceTag, Effect.succeed(new ConfigServiceImpl(...)))
```

---

## How to Add a New Adapter/Service

1. Add the contract to `packages/core/src/interfaces/` (interface + Tag).
2. Implement the adapter in `packages/adapters/src/` and create a Layer.
3. Add registration in [`packages/runtime/src/app-layer.ts`](../../packages/runtime/src/app-layer.ts) by merging the new Layer.
4. Add tests with a mock Layer.

---

## Testing Patterns

### Pure Function Tests

For utilities like `parseSpecialCommand` or `generateSessionId`:

```typescript
import { describe, expect, it } from "bun:test";
import { parseSpecialCommand } from "./parser";

describe("parseSpecialCommand", () => {
  it("should parse /help command", () => {
    const result = parseSpecialCommand("/help");
    expect(result.type).toBe("help");
  });
});
```

### Effect Tests with Mocked Layers

```typescript
const mockLogger: LoggerService = {
  debug: () => Effect.void,
  info: () => Effect.void,
  // ...
};

const testLayer = Layer.succeed(LoggerServiceTag, mockLogger);

const result = await Effect.runPromise(myEffect.pipe(Effect.provide(testLayer)));
```

---

## UI Architecture

`@jazz/cli` projects one semantic presentation document into OpenTUI's fullscreen
interface or the classic Ink interface. Effect services mutate the presentation
store; React consumes committed snapshots. Stable source IDs survive streaming,
settlement and resume. Geometry, scroll position, prompt continuations and secret
drafts remain outside persisted entries.

See [Conversation presentation](./presentation-documents.md) for ownership,
source links, and the version 3 history migration. Use the
[terminal rendering tests](./terminal-rendering-tests.md) to compare the emitted
terminal screen with the renderer's intended buffer.

---

## Why This Structure

- **Separates policy (core) from mechanics (adapters)**: makes it easy to:
  - Swap LLM providers
  - Substitute storage backends
  - Test core logic with deterministic mocks
- **Good for open-source**: Contributors can implement providers/adapters without changing core logic.

---

## Troubleshooting

- **Missing tag at runtime**: Ensure the Layer providing that tag is included in `createAppLayer`.
- **Circular dependency**: Use dependency injection (pass functions as parameters) instead of direct imports.
- **Context overflow**: The `Summarizer` automatically compacts context when tokens approach 80% of the limit.