How Charlie Works

Charlie is a cloud-hosted, asynchronous software-engineer teammate. He works through the systems engineering teams already use, including GitHub, Slack, and Linear, and returns work to those systems as reviewable results. A request does not need to begin in a separate chat or remain tied to one developer's computer.

This page follows Charlie's architecture from an incoming event through routing, durable execution, coordinated agent work, and external actions.

Charlie’s Architecture at a Glance

GitHub, Slack, and Linear events enter Charlie through ingestion, which validates, deduplicates, and enriches them. Routing then decides whether to start a durable Task, continue an active one, or drop the event.

The agent runtime executes the Task with context, tools, and delegation. It uses a devbox containing the relevant repositories, commands, CLIs, and scoped credentials to query and act on those connected systems, returning the result where the team already works.

Agents and Daemons

Agent tasks begin when a person mentions Charlie or assigns work to him. A daemon task begins on a schedule, or when a Signal matches a watch condition from a DAEMON.md file in the repo.

01

Agent

Human explicitly invokes Charlie.

Slack mention
“@Charlie, open a PR to implement…”
OR
GitHub PR review
“@Charlie fix <issues> with this PR”
Task
Runs as a general purpose Charlie agent with the Signal as context.
Unified agent runtime
02

Daemon

Event matches daemon watch condition.

GitHub event
PR #123 is ready for review.
AND
.agents/daemons/pr-review/DAEMON.md
Watch condition: PR ready for review.
Task
Runs as the role-specific agent defined by the DAEMON.md that watched for the event.
Unified agent runtime
Unified agent runtime

Each daemon lives at .agents/daemons/<daemon-id>/DAEMON.md on the repository's default branch. The file defines its purpose, activation conditions, routines, denials, and operating policy. Once merged and ingested, the role becomes eligible for activation. Its configuration remains visible and reviewable by the team.

Data Model and Flow

A webhook event records activity from GitHub, Slack, or Linear. An accepted event produces at most one enriched Signal, which gives routing the context it needs to add a Message to a Task's mailbox or create zero or more root Tasks. A Task is Charlie's durable record of agent work and can delegate child Tasks that retain their parent and root lineage. Scheduled daemon Tasks can also begin without a webhook event or Signal.

Webhook event
Signal
Task Mailbox
Daemon schedule
Root Task
Child Task
Webhook event
Signal
Task Mailbox
Signal
Daemon schedule
Root Task
Child Task

Routing and Activation

Routing consumes a Signal and produces a plan for what should happen next. It combines deterministic policy with semantic decisions: whether the Signal is eligible for normal Charlie agent work, whether it belongs to an active Task, which repository it belongs to, and which daemon roles apply.

For active work, Charlie compares the Signal with live root Tasks for the same customer. A follow-up Slack message can therefore be appended to the Task already handling the conversation instead of starting a competing second Task.

Repo inventory
Customer repositories Charlie can access.
Daemon definitions
DAEMON.md files from all customer repos.
Active tasks
Currently active tasks for the customer.
Signal
A normalized event with the context needed to decide what work it represents.
Repo inference Which repository owns or supplies context for it?
Admission Should work be done in response to this Signal?
Routing Is an active task already working on this?
Task Mailbox
The message is added to a task mailbox.
New Task
Agent and daemon work enters the same Task system.
No new work
Routing records why the Signal was dropped.

Work Persists and Executes

Tasks, Runs, and Mailboxes

A Task is Charlie's durable unit of agent work. It records the request, the selected repository and agent identity, relevant Signal context, lifecycle state, lineage, and final result.

Scheduled
Waiting for its execution time.
Queued
Ready for the scheduler to assign.
Running
Claimed by the agent executor.
Terminal
Succeeded, failed, canceled, or timed out.

Each Task has a durable mailbox. If a signal is correlated with active work, routing appends it to that Task instead of creating a competing root Task. The executor checks for mailbox messages and scheduler stop state at defined boundaries, adds new messages to the transcript, and uses them in subsequent work.

The Agent Runtime

Each turn and tool result is appended to a durable transcript. Phase and pending-tool state let the executor resume after a restart and report the final outcome to the scheduler.

Task
Signal, repository, daemon role, and durable state.
Agent version
Model, prompts, tools, and worker agents.
Mailbox + stop state
New input checked at phase boundaries.
Load context
Model turn
Tool calls + results
Checkpoint or finalize
Task outcome

Devboxes and External Actions

A devbox is Charlie's isolated Linux workspace. It contains the selected repository, runtimes, package managers, shell tools, and customer-scoped provider credentials. The agent starts or reuses it and records command results in the run transcript.

Provider CLIs query and update GitHub, Linear, Slack, and Sentry. A task tree may reuse one devbox or reference several devboxes when work spans repositories.

Agent runtime
Starts or reuses the devbox and runs commands.
Repository
Code, docs, skills, and instructions.
System
Linux, runtimes, packages, and shell tools.
Provider CLIs
gh, ch-linear, ch-slack, ch-sentry
Scoped access
Integration credentials and customer secrets.
Connected systems
GitHub, Linear, Slack, Sentry

Task Trees and Worker Agents

Charlie delegates work to worker agents. Each delegation creates a child Task with its own identity, lifecycle, role, and repository context while preserving parent and root lineage.

Workers can run in parallel. Workers can delegate to other workers. The parent lists, waits for, and inspects their status and evidence, then combines the results into one customer-facing outcome.

Parent Task

Delegates work, monitors progress, and awaits results.

Tools: delegate_task_to_<worker_name>, tasks_get, wait_for_task
Child Task(s)
Each child task has its own Task ID, role, lifecycle, and repository or devbox context. Child tasks are handled by worker agents and can delegate work, becoming the parent of each new child task they create.

The Complete System

Ingestion validates provider deliveries and turns supported events into enriched Signals. Routing decides what those Signals mean and writes new Tasks or messages for active Tasks. The Task system owns durable lifecycle, scheduling, mailbox state, and parent-child relationships. The agent runtime owns an execution attempt, including its context, transcript, model turns, and tool calls. Devboxes provide the isolated repositories, runtimes, command-line tools, and credentials used during execution.

Daemon definitions and schedules converge on the same Task system used for directed work. Once scheduled, both use the same runtime, tools, devboxes, and evidence infrastructure. Identifiers connect the original event to its routing decision, Task, execution, and external result.

The model reasons, calls tools, and delegates work. Services outside the model own Task status, mailbox persistence, and terminal state, so different workflows do not require separate execution systems.

Repository profiles
Records repositories and their available context.
Daemon inventory
Discovers daemon definitions in repos.
Schedule state
Daemon schedule tracking and activation.
GitHub
Slack
Linear
Ingestion
  1. GatewayReceives the webhook event.
  2. WebhooksValidates and deduplicates it.
  3. EnrichmentFetches context needed for routing.
Customer Knowledge Sync

Records repository profiles, discovers repository-owned daemon definitions, and produces scheduled activations.

Routing
  1. 1 Admission Rejects events Charlie should not handle.
  2. 2 Repository selection Infers the relevant repository when the event does not identify one.
  3. 3 Activation routing Classifies a new request, a follow-up to active work, or no action.
  4. 4 Daemon matching Evaluates each daemon and may activate zero, one, or many roles.
New agent Task Daemon Task(s) Message for active Task Drop
Task

Preserves each task’s lifecycle, mailbox, result, and lineage.

queuedrunningterminal

Mailbox messages and stop requests enter active work.

Root Task ├── Child Task │   └── Child Task └── Child Task
Execution attempt
  1. 01 Claim task
  2. 02 Fetch task and system context
  3. 03 Check mailbox and stop state
  4. 04 Call the model
  5. 05 Dispatch tool calls
  6. 06 Append tool results
  7. 07 Continue the loop or finalize
next model turn

Transcript and execution state are checkpointed between turns.

Worker agents

Delegation creates child Tasks in the same task tree.

exploreexecutereviewcommunications
Task tools

Inspects active and past work, workers, and transcripts.

tasks_listtasks_gettasks_transcript_listwait_for_task
Devbox tools

Starts or reuses environments and runs commands.

devbox_startdevbox_executedevbox_execution_status
General tools

Searches the web, inspects images, and maintains plans.

Devbox
Environment
Isolated Linux with runtimes, package managers, shell tools, and internet access.
Repository
The requested GitHub repository, branches, and working tree.
Working context
Repository-scoped context and daemon memory when available.
Provider access
Customer-scoped credentials for gh, ch-linear, ch-slack, and ch-sentry.

One task tree can start, reference, and hand off multiple devboxes.

GitHub
Reads code and PR state, then pushes commits, branches, PRs, and reviews.
Linear
Reads and updates projects, issues, and comments.
Slack
Reads channels and threads, then posts messages, replies, and reactions.
Sentry
Queries issues, events, traces, and diagnostic context.