# AGENTS.md instructions Source: https://docs.charlielabs.ai/AGENTS.md-instructions Design concise, scoped runtime instructions that improve agent decisions and discovery. `AGENTS.md` is a scoped runtime bootstrap contract. It gives an agent the minimum high-value context needed to understand its environment, make correct decisions, follow constraints, use the right workflows, and discover sources that would otherwise be easy to miss. It is not comprehensive documentation, a catalog of everything in the repository, or a guide for maintaining `AGENTS.md` itself. ## Decide what belongs inline Add content when at least one of these tests is met: * It has demonstrated behavioral value, or its absence has caused observable mistakes or wasted work. * It defines a historically misunderstood or rare but high-consequence boundary. * It provides durable company, product, customer, system, or operating context that changes which otherwise valid decision is best. * It routes work correctly or reveals a valuable tool, workflow, entrypoint, or source an agent may not discover on its own. “Important information” alone is not an inclusion test. For each candidate, weigh its value against both its direct cost and the context inherited by every nested scope. Account for duplication, staleness, maintenance burden, and the risk that an agent will apply the instruction too broadly or rigidly. Evaluate both the harm of omission and the harm of over-application. Tune instructions to observed behavior rather than accumulating generic best practices. One low-consequence mistake rarely justifies another permanent rule; a recurring or high-consequence failure may. ## Prefer enforcement and progressive disclosure Use the earliest reliable intervention. Prefer code structure, types, linting, formatting, tests, or CI when they can enforce an invariant effectively. Keep a concise instruction when enforcement is late, partial, expensive, unreliable, or unclear enough that an agent still needs guidance. Give detailed material one canonical home. When useful content is too large for runtime context: 1. Move it to the appropriate specification, runbook, or reference. 2. Keep the decision-critical summary or trigger inline. 3. Link directly to the canonical source and explain when and why to read it. Do not replace critical runtime instructions with bare links, and do not delete helpful authoritative material solely to make `AGENTS.md` shorter. ## Orient decisions before implementation State concise, durable context that changes tradeoffs: what the company or product does, who it serves, the role of this system, and any resource or operating priors that materially affect the best solution. Link to canonical sources for the extended context instead of making agents reconstruct purpose from low-level code. Keep current work, detailed customer evidence, ownership, versions, migration state, and other mutable facts in live or regularly reviewed sources whenever a pointer provides enough runtime value. If a mutable fact must remain inline, keep it brief and link to its authority. Avoid unanchored terms such as “currently,” “recently,” “new,” or “legacy for now”; use an absolute date or a live source. ## Layer instructions by scope * The root `AGENTS.md` contains only repository-wide context, rules, defaults, and discovery. * A nested `AGENTS.md` contains only subtree-specific additions, qualifications, explicit overrides, and local discovery. * Do not repeat parent wording. Review the combined parent and nested context, not each file in isolation. * State scope and precedence briefly when they are not obvious. Make overrides explicit instead of requiring the agent to infer them. ## Make links useful at decision time Curate high-value tools, workflows, real entrypoints, and source-of-truth files rather than listing the repository landscape. A path appearing in source code, `ls`, or `package.json` does not explain its authority or when to use it. For every non-obvious link, say what it contains, when to open it, and why it matters. Phrase links as an explicit condition, canonical target, and reason to read it. Link to the most specific canonical target. Verify that it contains the promised information, is accessible, is current or explicitly dated, and is written for the person or agent making the decision. ## Write for retrieval and correct application After a minimal scope statement, order content in the sequence an agent needs to decide and act. Put the most consequential mental models, boundaries, and guardrails first; follow with workflows, verification, conventions, and delivery guidance as needed for the scope. * Use operational, grepable headings and canonical terminology. * Keep related instructions together and near the workflow that triggers them. * Use short prose for coherent orientation and one-idea bullets for independent rules, references, and actions. * Use `must`, `never`, `always`, and `only` for invariants; `prefer` or `default to` for heuristics; and `before` or `when` for conditions. * State real exceptions and scope boundaries. Give every prohibition a safe alternative, a source to consult, or a condition for requesting judgment. * Name exact commands, paths, tools, and concepts. Keep broadly applicable verification commands inline; link to uncommon variants and troubleshooting. * Keep concise terminology distinctions that change decisions or have been repeatedly misunderstood. Link to comprehensive glossaries, inventories, data models, and architecture references. Avoid teaching examples, exhaustive inventories, motivational rhetoric, and task-specific checklists unless they independently pass the inclusion test. ## Keep authoring governance outside runtime files Runtime content tells agents how to operate in the repository. The process for authoring, evaluating, and maintaining that content belongs in an external policy or review workflow. Do not paste meta-instructions such as “keep this file short,” “avoid duplication,” “maintain `AGENTS.md`,” or “update this file when behavior changes” into runtime files. Size is a review signal, not the objective; retrieval and correct behavior are the objective. Use interaction audits, repeated corrections, incidents, rejected changes, support patterns, and representative evaluations as evidence. When a failure occurs, decide whether the best fix is clearer code, types, enforcement, tooling, canonical documentation, discovery guidance, or a runtime instruction. ## Review and refactor safely Before revising an instruction file: 1. Inventory the applicable root and nested files, then resolve the inherited instruction chain. 2. Read the complete target, parent instructions, linked canonical sources, and relevant evidence. 3. Measure the target and inherited context, then classify each block as keep, compress, move and link, delete, or replace with mechanical enforcement. 4. Review exact proposed wording, including interactions, misleading implications, and over-application risk. 5. Reread the complete result and validate formatting, links, duplication, scope, retrieval, and representative agent behavior. Review linked guidance when an important target moves or changes. Do not assume a rule became obsolete merely because its targeted failure stopped; first determine whether the risk disappeared, enforcement replaced it, or the rule is preventing it. ## Charlie-specific instruction loading Charlie loads shared `AGENTS.md` and `CLAUDE.md` instructions at any directory depth. Charlie-specific `CHARLIE.md` instructions load only at the repository root or anywhere beneath the root `.agents/` directory. `CHARLIE.md` is ordinary repository content, not a confidentiality, authorization, or access boundary. See [Customization](/customization) for the supported instruction, skill, and daemon surfaces. ## Source and ownership This page is Charlie Labs’ stable public representation and public guidance for AGENTS.md authoring. Charlie Labs maintains the detailed canonical strategy internally as the maintenance authority. ## Related docs * [Customization](/customization) * [Skills](/skills) * [How it works](/how-it-works) # Connect AI tools to the docs Source: https://docs.charlielabs.ai/connect-to-docs-mcp Use the unauthenticated Charlie Labs documentation MCP server with Codex, Claude Code, Cursor, or other MCP-compatible tools. Use the unauthenticated Charlie Labs documentation MCP server with Codex, Claude Code, Cursor, or any other MCP-compatible tool. ```text theme={null} https://docs.charlielabs.ai/mcp ``` # Daemons Source: https://docs.charlielabs.ai/daemons Understand what Charlie daemons are, how they wake, and how DAEMON.md controls behavior. **Human readers:** the fastest way to get started with daemons is to work directly with Charlie. **Charlie can help you** suggest where to start and add your first daemon. Use the prompts below to ask Charlie in Slack, GitHub, or Linear. ```markdown Learn about daemons theme={null} Explain what daemons are and how they work. ``` ```markdown Daemon use cases theme={null} What are some use cases for daemons? Which would you recommend starting with? ``` ```markdown Add a daemon theme={null} Open a PR to add a simple daemon to my repo. Explain what the daemon does and why you think it's a good place to start. ``` *** Daemons are repo-defined operating roles for Charlie. They give recurring operational debt an explicit owner instead of leaving it to ad hoc cleanup. A daemon lives at: `.agents/daemons//DAEMON.md` The daemon file tells Charlie: * its `purpose` * what `watch` conditions or `schedule` can wake it * what `routines` it should perform when it wakes * what `deny` rules tell it not to do * any additional operating guidance in the markdown body ## Start here If you are a human reader, the intended workflow is to work with Charlie. Ask Charlie to: * explain what daemons are * explain how to use daemons * recommend which daemons to add * create a new daemon file * edit an existing daemon file * help you test and iterate safely For the docs path, use the pages listed in **Where to go next** below. ## Use the daemon CLI Use the daemon CLI when you want the quickest path to browse examples, inspect an example before adapting it, scaffold a draft into a repository, or validate local daemon files. ```bash theme={null} bunx @charlie-labs/daemons --help bunx @charlie-labs/daemons list bunx @charlie-labs/daemons show pr-metadata bunx @charlie-labs/daemons add pr-metadata --dry-run bunx @charlie-labs/daemons validate --all ``` `list` and `show` are read-only browsing commands. `add --dry-run` previews the files that would be written, and `validate --all` checks local `.agents/daemons/**/DAEMON.md` files against the runtime file contract. Scaffolding writes draft files only. A scaffolded daemon does not become eligible for live activations until the change is merged to the repository default branch and Charlie ingests that merged version. ## What daemons are A daemon is a persistent role definition for recurring, bounded maintenance or operational work. Teams use daemons when there is ongoing maintenance or operational judgment that should be owned explicitly instead of handled ad hoc. Across activations, daemons can leverage prior activation logs to maintain state. Dedicated daemon memory is coming soon. ## What daemons are not A Charlie daemon is different from: * **Unix daemons:** a Charlie daemon is a repo-authored operating role, not a long-running OS process. * **Cron jobs:** a Charlie daemon is not just fixed predetermined steps on a timer. * **GitHub Actions:** a Charlie daemon is not a CI/workflow file tied to one pipeline. * **Fixed-rule bots:** watch matching is semantic rather than deterministic. * **Open-ended prompts:** a Charlie daemon is bounded by repo-local policy, `routines`, `deny`, and wake conditions. ## How daemons work today Today, each activation follows a wake/execute model: 1. the daemon wakes because `watch` matched or `schedule` fired 2. context from past activations of the daemon is loaded 3. Charlie executes the daemon’s routines within daemon constraints 4. the activation completes Supported wake sources are: * routed GitHub events * routed Linear events, including issue creation, issue comments, Charlie issue mentions, and issues assigned to Charlie * routed Slack events, including mentions and thread replies, channel messages, and DMs * scheduled wakes from the daemon’s `schedule` field For GitHub, event-driven activation uses the repo-scoped GitHub App installation. For Linear, it requires a connected Linear workspace and the issue's Linear team mapped to a repo with daemon inventory. For Slack, it requires a connected Slack workspace mapped to a repo with daemon inventory. Write `watch` around observable GitHub, Linear, or Slack events; use execution-time policy for derived state that requires API queries or analysis. Schedule-driven daemon activation uses the daemon’s `schedule` field when present as a standard five-field cron expression. ## `DAEMON.md` is the control surface `DAEMON.md` is the authored control surface for a daemon. The file has two parts: * YAML frontmatter for the formal contract * a markdown body for operating guidance The frontmatter contains the authored fields: * `id` * `purpose` * `watch` * `routines` * `deny` * `schedule` Minimum validity constraints: * `id`, `purpose`, and `routines` are required. * At least one of `watch` or `schedule` is required. The body is freeform markdown. Use it for the operating rules that make the daemon consistent, such as: * decision policy * limits * communication behavior * verification * freshness Those headings are conventions in the body, not extra frontmatter schema. Charlie treats the attached daemon file as the daemon’s primary role policy for each activation. ## Wake model A daemon can be: * watch-driven * schedule-driven * both `watch` describes event conditions that can wake the daemon. `watch` explains why a daemon wakes; it does not by itself authorize mutation. `schedule` describes time-based wakes using a standard five-field cron expression. If both are present, the daemon can wake from either path. At runtime, Charlie may refer to the daemon as: * Watch-only * Schedule-only * Hybrid Those are runtime-derived labels. Do not author them as frontmatter fields. ## Key terms * **daemon**: a repo-defined Charlie role for recurring maintenance or operational work * **daemon ID**: the canonical identifier, represented by the directory name and required `id` field * **daemon file**: the `DAEMON.md` file that defines the role * **frontmatter**: the YAML contract at the top of the file * **body**: the markdown guidance below the frontmatter * **wake / activation**: one execution caused by an event or schedule * **wake context**: the event or schedule reason the daemon woke for this activation * **watch**: event conditions that can wake the daemon * **routines**: the concrete operations the daemon performs when it wakes * **deny**: things the daemon must not do * **schedule**: timer-based wake configuration * **native surfaces**: the systems where teams already review and act on daemon output, such as GitHub, Linear, and Slack ## Where to go next * Read [Choosing daemons](/daemons/choosing-daemons) when deciding what daemon roles a team or repo should have. * Read [Writing and editing `DAEMON.md`](/daemons/writing-and-editing-daemon-md) when creating a new daemon or improving an existing one. * Use the [Review Checklist](/daemons/review-checklist) when reviewing daemon-file changes before merge. * Read [Testing and iterating on daemons](/daemons/testing-and-iterating-on-daemons) before broad rollout. * Read [`DAEMON.md` reference](/daemons/daemon-md-reference) when you need the exact file contract. * Use the daemon CLI for the quick path to browse examples and validate local daemon files. Start with `bunx @charlie-labs/daemons list`, `bunx @charlie-labs/daemons show `, and `bunx @charlie-labs/daemons validate --all`. * Use the examples repo for concrete reference patterns, but start with its [README.md](https://github.com/charlie-labs/daemons/blob/master/README.md) and treat the examples as patterns to adapt, not as files to copy blindly. # Choosing daemons Source: https://docs.charlielabs.ai/daemons/choosing-daemons Choose the right daemon roles using practical selection heuristics, scoping rules, and rollout fit. **Human readers:** the fastest way to get started with daemons is to work directly with Charlie. **Charlie can help you** suggest where to start and add your first daemon. Use the prompts below to ask Charlie in Slack, GitHub, or Linear. ```markdown Learn about daemons theme={null} Explain what daemons are and how they work. ``` ```markdown Daemon use cases theme={null} What are some use cases for daemons? Which would you recommend starting with? ``` ```markdown Add a daemon theme={null} Open a PR to add a simple daemon to my repo. Explain what the daemon does and why you think it's a good place to start. ``` *** Before choosing daemon roles, read [Daemons](/daemons). In this docs set, a daemon is a repo-defined operating role for Charlie, authored in `.agents/daemons//DAEMON.md`. That is not the same thing as a Unix daemon, a cron job, a GitHub Action, or a generic background agent. Use this page when Charlie or a human is deciding what daemon roles a team or repo should have. This page is about choosing the right daemon, not about the exact file format. For the file contract, read [DAEMON.md reference](/daemons/daemon-md-reference). For how to write or edit a file, read [Writing and editing DAEMON.md](/daemons/writing-and-editing-daemon-md). ## How to identify daemon opportunities Do not start by asking, “What clever daemon could we build here?” Start by asking: * What recurring maintenance or operational work is happening here? * What recurring maintenance or operational work is not happening, but should be? * What low-grade operational debt is accumulating because nobody consistently owns it? Daemons are a good fit when the work is recurring, bounded, and worth doing continuously. ## Selection heuristics Charlie should apply When choosing candidate roles, Charlie should usually: * prioritize the most repetitive and under-owned maintenance work * prefer narrow roles with obvious activation conditions * prefer daemon shapes that produce legible output on native surfaces “Obvious activation conditions” means concrete observable evidence: a PR opened, a review submitted, a file path changed, a stale-item threshold crossed, or a recurring survey on a schedule. It does not mean vague intent like “when the repo needs help.” Good daemon candidates need wake conditions based on events or signals Charlie can actually observe. If the desired target state requires a follow-up query or derived analysis, wake on the closest observable event or schedule, then inspect the derived state during execution. If a proposed role is broad, hard to wake reliably, or hard to review where the team already works, it is probably not the right first daemon. ## What makes a good daemon candidate A good daemon candidate is: * **recurring**: the work comes up repeatedly * **bounded**: the role can be described clearly enough to know what is in and out of scope * **observable**: there are events, schedules, or state changes Charlie can use to wake the daemon * **reviewable**: the daemon’s outputs can be seen and judged on native surfaces * **valuable even when done incrementally**: each activation can do a small amount of useful work A strong first daemon is usually narrow. It does one ongoing job well and stops/no-ops, comments with a blocking reason, or asks for specific human input when work falls outside that job. Scheduled daemon roles are strongest when each activation can create value on its own. Frame them as recurring surveys, checks, or reconciliation passes, not as open-ended background ambition. Activations should stay bounded, but runs can still use context from prior run logs. ## Daemon or one-off Charlie task? Use a daemon when the same bounded role should wake repeatedly and add value over time. Use a normal Charlie task when: * the work has a clear finish line * the request is specific to one temporary push, investigation, or project moment * the work depends heavily on transient human context * the work is useful now but not worth maintaining as an ongoing role A useful test is: if this were handled well once, would we still want the same role to keep waking later? If yes, it may be a daemon. If no, it is probably a one-off Charlie task. ## What not to daemonize Do not daemonize work that is: * one-off * vague * broad enough to read like “improve everything” * dependent on hidden human context that the daemon cannot reliably infer * dependent on continuously running process semantics instead of bounded activations with clear wake signals * too risky to act on without explicit stop/comment/action boundaries * only useful as an ad hoc investigation or project-specific push If the work is better framed as one normal task for Charlie, use a normal task instead of a daemon. ## Use-case families The families below are representative, not exhaustive. They are broader than the current public example set. Use the nearest example as a pattern anchor, not as a boundary on what is allowed. ### PR maintenance Use a daemon when PRs routinely: * go stale * lose mergeability * have weak titles or descriptions * miss expected evidence * accumulate fixable hygiene issues that nobody owns * carry review feedback that needs ongoing triage Example repo-local daemon files: `.agents/daemons/pr-metadata/DAEMON.md`, `.agents/daemons/pr-review-triage/DAEMON.md`, `.agents/daemons/pr-check-repair/DAEMON.md`, `.agents/daemons/pr-feedback-repair/DAEMON.md`, and `.agents/daemons/pr-merge-conflict-repair/DAEMON.md`. ### Issue or project-graph hygiene Use a daemon when: * issue status drifts from reality * labels are missing or inconsistent * PRs and issues are not linked correctly * completed work is not being closed or updated * project metadata is expected to stay structured, but nobody maintains it * new issues need labels, owners, or reproduction details before work can start * linked PR state needs regular reconciliation with issue status * ownership or follow-up expectations become unclear as issue threads evolve ### Documentation freshness Use a daemon when: * docs drift behind implementation * README and setup instructions become unreliable * operational docs or runbooks rot quietly * documentation maintenance is clearly needed but never prioritized ### Dependency or codebase maintenance Use a daemon when: * dependencies age without review * low-risk mechanical fixes pile up * dead code or scaffolding accumulates * low-grade maintenance work exists but nobody owns it continuously ### Bug or error triage Use a daemon when: * bug reports or alerts pile up without triage * repeated issues disappear into noise * someone needs to maintain a structured view of what deserves human attention * duplicates, conflicts, or stale feedback regularly waste time * bug reports arrive in support channels and need filing, deduping, or linking to the right issue * incident or support threads collect decisions and blockers that should be summarized * recurring support summaries would make the highest-risk reports easier to review ### Scheduled surveys, checks, or reports Use a daemon when: * the most useful work is not tied to one event * you need recurring review of a surface * the job is “notice what needs attention on a schedule” rather than “react immediately to one signal” * the best role is periodic reconciliation, ranking, or reporting ## When to choose `watch`, `schedule`, or both Choose **watch** when the daemon should react to a discrete event. Choose **schedule** when the daemon should wake on time, survey a scope, and decide what matters now. Choose **both** when the daemon needs: * immediate reaction to some events * plus periodic review for issues that may not emit a useful event Use `watch` for event-driven work. Use `schedule` for time-driven work. Use both only when both wake postures materially help the same daemon role. Signal-driven daemon inference can evaluate routed GitHub, Linear, and Slack events once Charlie can infer the relevant repo and daemon inventory. For Linear-heavy roles, make the issue team mapping and semantic `watch` evidence explicit. For Slack-heavy roles, make the workspace mapping and semantic `watch` evidence explicit. Use `schedule` or a hybrid when the role also needs periodic review beyond individual events. For survey-style event daemons, wake on the narrow event that makes the survey newly relevant, then inspect candidates during execution. Do not broaden the wake condition just to encode every possible candidate state. ## How to scope a daemon well This section is about choosing clean daemon role boundaries. It is not a recommendation to add a generic body section named for scope; hard target boundaries should live in frontmatter when possible, with body policy reserved for nuanced target selection. Keep one daemon when: * the work serves one narrow purpose * the wake logic is closely related * the risk profile is similar * the outputs belong on the same native surfaces Split into multiple daemons when: * the role is trying to do too many unrelated things * some routines need very different wake logic * some routines need very different limits or stop/comment/action boundaries * some routines would be easier to reason about as smaller roles * different kinds of output belong on different native surfaces When in doubt, split broad ideas into smaller daemon candidates and start with the narrowest useful version. If a daemon would need many runtime branches for package manager, issue tracker, provider, or platform-specific behavior, prefer a narrower daemon or a single configured variant. A specific, adapted daemon is usually easier to trust than a generic daemon that guesses its operating mode. A good first daemon is usually narrower than the daemon you might eventually want. ## How to choose the first daemon Do not start with the most ambitious daemon. Start with the recurring maintenance work that is: * clearly under-owned * high-friction for the team when neglected * easy to bound * easy to review on native surfaces * likely to create value without high-risk side effects * likely to produce signal rather than noise In practice, that usually means starting with one obvious maintenance role rather than a “repo caretaker” that tries to own everything. ## Value versus noise A daemon is more likely to add value when: * its wake conditions are concrete * its outputs appear where the team already reviews that kind of work * its actions are easy to verify * its scope is narrow enough to explain in one sentence * each activation can do a small amount of useful work without broad wandering Warning signs that a daemon will mostly create noise: * the wake condition is vague * the role touches too many unrelated surfaces at once * the daemon mostly restates known information without changing decisions or state * the outputs land somewhere the team does not already monitor * the role depends on too much hidden human context * the daemon would create follow-up work faster than the team can absorb it * the role is so broad that almost every activation would need judgment outside clear boundaries ## What Charlie needs in order to recommend daemons well When asking Charlie to recommend daemons, provide: * the recurring maintenance problems you want daemons to own * the repo or team surfaces where that work appears today, such as GitHub, Linear, or Slack * the areas of the repo or workflow that matter most * any boundaries the daemon should respect * any especially noisy areas that should be avoided If the team already has strong norms, include them. Daemon selection is much better when Charlie knows what “healthy” looks like for this team. ## Native-surface fit Choose outputs that match the system of record the daemon is maintaining. As a rule: * use GitHub-facing output for PR, repo, and codebase maintenance * use Linear-facing output for issue or project-graph hygiene * use Slack-facing output for summaries, low-blast-radius rollout, or cases where the right first step is visibility rather than mutation A daemon should produce work where the team already expects to see and review that kind of work. If a daemon’s output would feel out of place on the target surface, re-scope the daemon or choose a different surface. ## How to use examples when choosing daemons Start with the daemon CLI so you can browse the current catalog and inspect the nearest pattern before opening source files. ```bash theme={null} bunx @charlie-labs/daemons list bunx @charlie-labs/daemons show pr-metadata ``` Use `list` to see available example IDs. Use `show ` to inspect whether an example is ready to adapt: readiness, required and optional integrations, support files, and required adaptation notes are surfaced before you copy anything. Then use the examples repo README as a supplemental browsing path: [examples repo README](https://github.com/charlie-labs/daemons/blob/master/README.md). Use examples to: * find the nearest existing pattern * calibrate scope * see how similar daemon roles are bounded * compare different wake shapes and output postures * understand how narrow, explicit roles are actually written Do not treat the examples as the full space of valid daemons. Use them as pattern anchors, not as a menu of all allowed roles. If no example exactly matches the repo’s problem, choose the nearest pattern and adapt the role to the repo’s actual maintenance gap. Where the current public examples are PR-heavy, take the role shape, scoping discipline, and output posture from them rather than copying the literal surface. ## A simple selection rubric A daemon idea is promising when the answer is “yes” to most of these: * Is this work recurring? * Is the role narrow enough to explain in one sentence? * Can the daemon wake from clear events, schedules, or both? * Can the team review the daemon’s outputs on native surfaces? * Would small, repeated activations be useful here? * Is this likely to create signal rather than noise? * Can the daemon be rolled out narrowly first? A daemon idea is weak when the answer is “no” to most of these. ### Recommendation clarity check for daemon recommendations When Charlie recommends daemons, the recommendation should make these points explicit: * the daemon’s purpose * why this role is worth creating now * whether it should be watch-driven, schedule-driven, or hybrid * what makes the role narrow enough to start safely * where the daemon’s output should appear * which example daemon is the closest analog, if any If Charlie cannot explain those clearly, the daemon idea is probably not ready. # DAEMON.md reference Source: https://docs.charlielabs.ai/daemons/daemon-md-reference Exact DAEMON.md authored contract, validation rules, and support-tree semantics. **Human readers:** the fastest way to get started with daemons is to work directly with Charlie. **Charlie can help you** suggest where to start and add your first daemon. Use the prompts below to ask Charlie in Slack, GitHub, or Linear. ```markdown Learn about daemons theme={null} Explain what daemons are and how they work. ``` ```markdown Daemon use cases theme={null} What are some use cases for daemons? Which would you recommend starting with? ``` ```markdown Add a daemon theme={null} Open a PR to add a simple daemon to my repo. Explain what the daemon does and why you think it's a good place to start. ``` *** This page defines the authored `DAEMON.md` contract. A daemon is not a Unix daemon, cron job, GitHub Action, or generic background agent. In this system, `DAEMON.md` is the authored control surface for a repo-local Charlie role, while runtime metadata such as activation mode is derived rather than authored directly. Use this page when you need the exact file format, field definitions, validation rules, and support-tree semantics. For guidance on when to use a daemon, read [Choosing daemons](/daemons/choosing-daemons). For guidance on how to write a good daemon, read [Writing and editing `DAEMON.md`](/daemons/writing-and-editing-daemon-md). For concrete examples, start from the examples repo README/index. ## Directory structure A daemon is a directory containing a `DAEMON.md` file. ```text theme={null} .agents/daemons// DAEMON.md scripts/ # optional references/ # optional ``` ## Full file format `DAEMON.md` must contain: 1. `---`-delimited YAML frontmatter that parses to an object/map 2. a markdown body below the closing frontmatter delimiter The authored file shape is: ```md theme={null} --- id: purpose: watch: - routines: - deny: - schedule: "" --- ``` The file is invalid if: * the opening or closing `---` delimiter is missing * the frontmatter is malformed YAML * the frontmatter does not parse to an object/map ## Field-by-field reference ### Authored frontmatter fields | Field | Required | Type | Meaning | | ---------- | -------- | --------------- | --------------------------------------------------------------------- | | `id` | Yes | string | Canonical daemon identifier. Must exactly match the daemon path slug. | | `purpose` | Yes | string | One sentence describing the daemon’s intended outcome. | | `watch` | No | list of strings | Event conditions that wake the daemon. Natural language. | | `routines` | Yes | list of strings | Operations the daemon performs when activated. Natural language. | | `deny` | No | list of strings | Behavioral prohibitions for the daemon. Natural language. | | `schedule` | No | string | Timer-based wake configuration. Standard five-field cron. | ### `id` `id` is the canonical daemon identifier. Rules: * required * non-empty * must exactly match the daemon directory name ### `purpose` `purpose` is one sentence describing the daemon’s intended outcome. Write intent, not mechanics. ### `watch` `watch` is a list of natural-language event conditions that can wake the daemon. Rules: * optional * if present, must be a YAML list of non-empty strings * should describe discrete, observable events Use provider-visible event language rather than raw webhook names. Keep provider-specific examples and routing requirements in [Writing and editing `DAEMON.md`](/daemons/writing-and-editing-daemon-md) and the relevant integration docs. Use `schedule` for cron-based wakes. Do not put cron timing in `watch`. ### `routines` `routines` is a list of natural-language operations the daemon performs when it wakes. Rules: * required * must be a YAML list of non-empty strings * must include at least one entry * each entry should describe a concrete, finite operation ### `deny` `deny` is a list of things the daemon is told not to do. Rules: * optional * if present, must be a YAML list of non-empty strings ### `schedule` `schedule` is timer-based wake configuration. Rules: * optional * when present with meaningful text, must be a string * blank or whitespace-only values are treated as `null` * must be valid standard five-field cron * evaluated in UTC Supported cron semantics today: * standard five-field cron only * comma-separated lists * ranges * stepped ranges * `7` in day-of-week is treated as `0` (Sunday) Day matching follows normal cron-style rules: * if both day-of-month and day-of-week are wildcard, any day matches * if one is wildcard, the other controls * if both are restricted, the scheduler matches `day-of-month OR day-of-week` ## Validation rules These are the key authored validation rules. * `id` is required. * `id` must exactly match the daemon path slug. * `purpose` is required. * `routines` is required. * `routines` must be a YAML list of strings and must contain at least one non-empty entry. * `watch`, when present, must be a YAML list of non-empty strings. * `deny`, when present, must be a YAML list of non-empty strings. * `schedule`, when present with meaningful text, must be a string. * Blank or whitespace-only `schedule` values are treated as `null`. * At least one activation field must be present: `watch` or `schedule`. * `schedule` must be a valid five-field cron expression. * Activation mode is derived from `watch` and `schedule`; do not author it directly. Runtime-derived activation labels are: * **Watch-only**: `watch` present, `schedule` absent * **Schedule-only**: `schedule` present, `watch` absent * **Hybrid**: both present ## Validate with the CLI Use the daemon CLI to validate runtime daemon files in a repository. ```bash theme={null} bunx @charlie-labs/daemons validate .agents/daemons/pr-metadata/DAEMON.md bunx @charlie-labs/daemons validate --all bunx @charlie-labs/daemons validate --all --json ``` `validate ` checks one file. `validate --all` discovers `.agents/daemons/**/DAEMON.md` files from the current repository. Add `--json` when automation needs structured output. Validation checks the runtime file contract: frontmatter syntax, allowed and required fields, activation fields, cron syntax, a non-empty markdown body, and path-aligned IDs. ## Field name disambiguation Use the authored field names exactly as written in this page. | Use this | Do not use | | ---------- | ------------- | | `id` | `name` | | `purpose` | `description` | | `watch` | `triggers` | | `routines` | `actions` | | `deny` | `disallowed` | `name` is not a valid authored field. Use `id`. Do not invent extra frontmatter fields. Do not add runtime-derived labels such as activation mode to frontmatter. ## Body semantics The markdown body below the frontmatter is freeform. It is meaningful at runtime: the body is carried into execution and interpreted as part of the daemon’s operating brief. Because the body is interpreted at runtime, do not use it for install-time setup, copy-time adaptation, or tutorial notes. Use it for operational guidance such as: * decision policy * communication policy * verification policy * freshness policy * concurrency policy * output format * limits * priority * thresholds * conventions * ignore patterns * examples There are no required body headings. Headings such as `Decision policy`, `Limits`, `Communication policy`, and `Verification and freshness` are conventions, not schema. ## Support tree semantics A daemon directory may include optional subdirectories alongside `DAEMON.md`: ```text theme={null} .agents/daemons// DAEMON.md scripts/ references/ ``` Use: * `scripts/` for executable helpers or deterministic utilities the daemon can call * `references/` for policy docs, templates, style guides, or other context the daemon can read but should not modify If a daemon relies on a helper script, document the required inputs, output shape, pagination or completeness expectations, and what the daemon should do when the script cannot return complete context safely. ## Authoring conventions that help avoid validation issues Use these conventions consistently: 1. **Canonical field order.** When fields are present, use this order: Treat this order as a consistency/readability convention; parsers must not require it. * `id` * `purpose` * `watch` * `routines` * `deny` * `schedule` 2. **Path-aligned IDs.** Keep the directory name and the `id` value exactly aligned. 3. **Stable naming.** Use only the canonical authored field names: `id`, `purpose`, `watch`, `routines`, `deny`, and `schedule`. ## Examples For concrete patterns, use the examples repo index: [Examples repo README](https://github.com/charlie-labs/daemons/blob/master/README.md). # Review Checklist Source: https://docs.charlielabs.ai/daemons/review-checklist Review daemon-file pull requests for contract, safety, repeatability, and proof gaps before merge. ## 1. Frequently broken rules Use these as first-pass review gates before reading the detailed checklist.
  1. For new daemon files, check line count and simplicity first. `DAEMON.md` should normally be 50–100 lines. Reject speculative edge case handling, all-use-case coverage, verbose idempotency logic, generic filler, or body prose that exists only to sound complete.
  2. Put the durable daemon contract in frontmatter. Identity, purpose, wake conditions, core routines, hard prohibitions, and schedules belong in `id`, `purpose`, `watch`, `routines`, `deny`, and `schedule`, not body prose.
  3. Do not duplicate frontmatter in the body. If a body section restates `purpose`, `watch`, `routines`, or `deny`, delete it or move only the missing hard rule into frontmatter.
  4. Do not restate the wake model in the body. The body must not repeat the `watch` list, restate the `schedule`, or describe the daemon's activation mode as prose.
  5. Keep the body short and behavioral. Every body paragraph must change how the daemon decides, verifies, communicates, limits scope, coordinates, or no-ops. Remove generic filler, repeated policy, tutorial notes, and setup instructions.
  6. `purpose` must be one short outcome statement. It must describe the end state the daemon exists to maintain, not a list of scans, API calls, messages, implementation mechanics, historical context, activation details, deny rules, quiet/no-op policy, or other runtime guidance.
  7. Write `routines` as concrete wake-time operations. Each routine must be finite and verifiable. Advice belongs in body guidance; negative guardrails belong in `deny` or body policy.
  8. Use explicit, resolving references and destinations. Daemon IDs, docs paths, pinned refs, example names, issue or project identifiers, Slack channels, GitHub labels, and repo-specific configuration must be current and unambiguous.
## 2. Inspect every changed daemon file
  1. Reviewers must inspect the canonical `.agents/daemons//DAEMON.md` file.
  2. Reviewers must inspect changed `scripts/**` and `references/**` files.
  3. Reviewers must read nearby support files when the changed behavior depends on them and must flag stale, hidden, contradictory, or disconnected guidance.
  4. The PR must stay narrowly scoped to the requested daemon change; unrelated or unnecessary additions must be removed.
## 3. Review the `DAEMON.md` contract Use the [`DAEMON.md` reference](/daemons/daemon-md-reference) when you need the full authored contract. ### Required file shape
  1. `DAEMON.md` must live at `.agents/daemons//DAEMON.md`.
  2. `DAEMON.md` must start with `---`-delimited YAML frontmatter that parses to an object/map.
  3. `DAEMON.md` must have a non-empty Markdown body below the closing delimiter.
### Authored fields and structural rules
  1. The frontmatter must include `id`, `purpose`, and `routines`.
  2. `id` must exactly match the `` path slug.
  3. The frontmatter must include at least one activation field: `watch` or `schedule`.
  4. `routines` must be a YAML list with at least one non-empty string. When present, `watch` and `deny` must also be YAML lists of non-empty strings.
  5. The frontmatter must use the canonical authored field names and must not invent fields or substitute `name`, `description`, `triggers`, `actions`, or `disallowed` for `id`, `purpose`, `watch`, `routines`, or `deny`.
### Field quality
  1. `purpose` must be one short outcome statement. It must describe the end state the daemon exists to maintain, not how the daemon works, why it was created, when it wakes, when it stays silent, or what it must not do.
  2. routines must contain only concrete, finite, verifiable operations the daemon performs when it wakes. Advice belongs in the body; negative guardrails belong in deny or body policy.
  3. `deny` must cover plausible adjacent risky shortcuts and must fail closed for important ambiguity.
  4. `watch` must use semantic matching language and describe provider-visible observable events rather than raw webhook labels or derived-state queries that belong in execution-time checks.
  5. `watch` entries must not be vague, brittle, catch-all, or broadly overlapping in ways that can produce duplicate activations.
  6. When present, `schedule` must use standard five-field cron in UTC. If both day-of-month and day-of-week are restricted, reviewers must account for ordinary cron `day-of-month OR day-of-week` semantics.
### Validate with the CLI Run the daemon CLI from the repository that contains the changed daemon file to confirm the authored contract is valid. ```bash theme={null} bunx @charlie-labs/daemons validate .agents/daemons//DAEMON.md ``` Use `bunx @charlie-labs/daemons validate --all` when the PR changes multiple daemon files. ## 4. Review body guidance Use [Writing and editing `DAEMON.md`](/daemons/writing-and-editing-daemon-md) for deeper authoring guidance.
  1. The Markdown body must contain runtime policy rather than setup instructions or tutorials.
  2. The body must not duplicate frontmatter content. If body guidance restates `purpose`, `watch`, `routines`, `deny`, or `schedule`, reviewers must delete it or move only the missing hard rule into frontmatter.
  3. The body must add targeted guidance only where it materially improves behavior: decision terms, output format, communication and silent no-op policy, verification and freshness, limits, target selection and ignore patterns, coordination and concurrency, human authority, and clarifying examples.
  4. The body must define ambiguous terms once and must remove duplicative or overly verbose content. It must rely on frontmatter and linked canonical sources instead of restating them.
## 5. Review support files
  1. Reviewers must inspect the full daemon support tree when it changes.
```text theme={null} .agents/daemons// DAEMON.md scripts/ references/ ``` ### `scripts/`
  1. Scripts must be used for executable, deterministic helpers.
  2. Scripts must document required inputs, output shape, pagination or completeness expectations, and safe behavior when complete context is unavailable.
### `references/`
  1. References must be used for read-only policy, templates, guides, examples, or other context.
  2. `DAEMON.md` must say when and how to use any reference the daemon relies on.
## 6. Review repeatability and safety
  1. Wake context must be treated as activation context rather than mutation authorization. Current provider state must be refetched immediately before consequential writes.
  2. Limits must be added when work or visible noise can sprawl.
  3. For branch mutation, force-push must be denied by default. If repository policy permits it, the daemon must require fresh remote state and `--force-with-lease`. It must state whether fork or cross-repository branches are out of scope.
## Learn more * [Daemons](/daemons): concepts, wake model, and `DAEMON.md` as the control surface. * [Choosing daemons](/daemons/choosing-daemons): how to identify and scope daemon opportunities. * [Writing and editing `DAEMON.md`](/daemons/writing-and-editing-daemon-md): guidance for clear, narrow, safe daemon files. * [`DAEMON.md` reference](/daemons/daemon-md-reference): exact authored contract, validation rules, and support-tree semantics. * [Testing and iterating on daemons](/daemons/testing-and-iterating-on-daemons): testing, observation, and iteration guidance. # Testing and iterating on daemons Source: https://docs.charlielabs.ai/daemons/testing-and-iterating-on-daemons Roll out daemons safely, reduce blast radius, and iterate based on observed behavior. **Human readers:** the fastest way to get started with daemons is to work directly with Charlie. **Charlie can help you** suggest where to start and add your first daemon. Use the prompts below to ask Charlie in Slack, GitHub, or Linear. ```markdown Learn about daemons theme={null} Explain what daemons are and how they work. ``` ```markdown Daemon use cases theme={null} What are some use cases for daemons? Which would you recommend starting with? ``` ```markdown Add a daemon theme={null} Open a PR to add a simple daemon to my repo. Explain what the daemon does and why you think it's a good place to start. ``` *** Use this page when a daemon file already exists and you need to roll it out safely, observe its behavior, and tighten or widen it over time. ## Start with the rollout mindset Early testing is not about proving the daemon can do everything. Early testing is about proving the daemon behaves correctly and quietly under narrow, intentional conditions. Use your team’s normal activation workflow for rollout. A daemon becomes eligible for live activations after both are true: * the updated `DAEMON.md` is merged to the repo’s default branch * Charlie has ingested that merged version Once both are true, the daemon is live: * current `watch` conditions can begin matching * a current `schedule` can begin driving scheduled activations * the first question is not “can it do more?” but “can it behave correctly under narrow conditions?” Start narrow. Prefer low-blast-radius outputs first. Widen only after repeated correct behavior. Use the daemon file itself to enforce narrowness. Do not rely on people remembering to be careful during rollout. ## Keep the file model straight The authored frontmatter fields are: * `id` * `purpose` * `watch` * `routines` * `deny` * `schedule` `schedule` uses standard five-field cron syntax. The markdown body can include headings like Decision policy, Communication policy, Verification and freshness, Limits, Coordination, and Ignore patterns, but those headings are recommended conventions, not frontmatter schema. Activation-mode labels such as Watch-only, Schedule-only, and Hybrid are runtime-derived from `watch` and `schedule`. Authors do not write them as frontmatter fields. ## What you can observe today Today, there is no dedicated daemon activity or logs page in the Charlie dashboard. Observe daemon behavior on native surfaces: * GitHub * Slack * Linear Because there is no dedicated activity page today, human rollout verification usually means inspecting the daemon’s visible work on those systems. That is different from daemon-internal verification. If the daemon file says the daemon must run checks, tests, API probes, freshness checks, or other validation before a consequential write, confirm the daemon actually performed that verification before trusting the activation. ## Containment levers Use these authoring levers to reduce blast radius before rollout. ### Narrow `watch` Make `watch` conditions specific enough for early rollout without making them misleading as a durable contract. Examples of narrow testing patterns: * only react to PRs opened by the person creating and testing the daemon * only react to a labeled test PR * only react to a deliberately narrow category of change * only react to a surface where the tester can inspect every result closely Temporary overfitting is acceptable during rollout, such as limiting activation to a test label, test branch, or test author. Remove that overfitting before normal rollout unless it is part of the daemon’s real long-term role. ### Narrow target boundaries Limit where the daemon pays attention. Put hard target boundaries in `watch`, `routines`, or `deny` when possible; use body policy only for nuanced target-selection behavior. Examples: * only a specific directory or file family * only PRs targeting one branch or branch pattern * only one issue label or PR label category * only a sandbox repo for the first rollout ### Add Ignore patterns Skip noise early. Examples: * ignore bot-authored activity * ignore generated files * ignore surfaces or categories that would create noisy false positives during testing ### Add stronger `deny` If the daemon could take risky actions, deny them during early rollout and widen later only if needed. ### Add Limits Constrain the daemon’s output volume. Examples: * at most N items per activation * no more than N visible actions per day * stop producing new work when too much prior daemon work is still waiting on humans ### Add Coordination Coordination rules are a containment lever, not just a cleanup detail. Examples: * do not comment where a human review is already in progress * do not duplicate work another daemon already started * use a label or ownership convention so other daemons can filter early-rollout work ### Constrain output surfaces first Prefer outputs that only the tester or a very small audience will see first. Examples: * send Slack DMs to the daemon author first * comment only on a labeled test PR * keep early outputs on one low-blast-radius surface ### Constrain who or what the daemon touches first Keep the first target set intentionally small. Examples: * only act on PRs opened by the daemon author * only act in a sandbox repo first * only act on a test branch pattern first * only act on one issue label or PR label first ## Testing by activation type Event wakes respond to a triggering signal. Scheduled wakes survey their target set and prioritize within it. Hybrid daemons need both postures, so test them separately at first. ### Watch-driven daemons Use watch-driven testing when the daemon should react to a discrete event. Current rollout facts that matter: * event-driven wakes can come from routed GitHub, Linear, and Slack events once repo inference selects a repo with daemon inventory * Linear tests depend on a connected Linear workspace, the issue's Linear team mapping, and routing content that clearly contains the observable trigger; Slack tests depend on a connected Slack workspace and Slack workspace mapping * `watch` conditions are interpreted semantically, so concrete observable phrasing is more reliable than vague wording A good rollout pattern for a watch-driven daemon is: 1. make `watch` narrow 2. constrain target boundaries, Ignore patterns, and Coordination 3. add strong `deny` and Limits 4. create a small number of deliberate test events 5. inspect visible output on GitHub, Slack, or Linear 6. tighten or widen the file and repeat If the daemon is noisy, first ask: * did it wake for the wrong event? * or did it wake correctly and act too broadly once awake? Wrong wakes usually point to `watch`, target boundaries, or Ignore patterns. Wrong actions usually point to `routines`, `deny`, Limits, Coordination, or other body guidance. #### Linear testing recipe Use a Linear test when the daemon should respond to supported issue events. 1. Confirm the Linear integration is connected and the Linear team you will test in is mapped to the intended repo. 2. Pick one low-risk issue path to test. 3. Use concrete `watch` wording that tests a supported issue create or issue-comment create event rather than the repo/team mapping precondition, such as “A new Linear issue contains the exact phrase `daemon-test-12345`” or “A Linear issue comment contains the exact phrase `daemon-test-12345`.” 4. Trigger that supported low-risk event by creating the test issue or adding the unique phrase as a normal issue comment. Use Charlie mention or assignment only when intentionally testing direct-invocation routing. 5. Inspect the daemon’s visible output on Linear and any linked GitHub or Slack surface. 6. Confirm it did not act on unrelated issues outside the mapped team or daemon scope. #### Slack testing recipe Use a Slack test when the daemon should respond to channel, thread, or DM activity. 1. Confirm the Slack integration is connected and the Slack workspace is mapped to the intended repo. 2. Pick one low-risk channel, thread, or DM path to test. 3. Use concrete `watch` wording, such as “A Slack thread reply is added in the named support channel.” 4. Trigger one event: a mention, thread reply, broader channel message, or DM. For broad message wakes, narrow matching to intentional channels in `watch` wording or body policy. 5. Inspect the daemon’s visible output in Slack and any linked Linear or GitHub surface. 6. Confirm it did not respond to unrelated channel traffic. ### Schedule-driven daemons Use schedule-driven testing when the daemon should wake on time and survey what needs attention inside a defined scope. Current rollout facts that matter: * invalid cron strings are rejected when daemon config is refreshed * if a schedule update is invalid and a previous valid schedule already exists, Charlie keeps the previous valid schedule until the cron value is fixed * schedule-based activations do not replay a full backlog of missed ticks * after downtime, the scheduler catches up at most one missed tick, then continues from current time A good rollout pattern for a schedule-driven daemon is: 1. start with conservative body guidance and low-blast-radius outputs 2. add strong Limits 3. make target boundaries intentionally narrow 4. choose a schedule that lets the tester observe the first activations closely 5. inspect the resulting visible actions 6. widen gradually only after behavior is consistently correct If the daemon is too noisy on schedule: * tighten target boundaries * add or strengthen Limits * narrow the `routines` to the minimum correct work If the daemon is too passive on schedule: * inspect whether target boundaries are too narrow * inspect whether `deny` or Limits are over-constraining it * inspect whether `routines` describe the intended action clearly enough ### Hybrid daemons Use hybrid testing when the daemon needs both event-driven reaction and scheduled review. Do not test both wake paths broadly at once. Get one wake path behaving well first, then add the second. A good order is: 1. test the lower-blast-radius path first 2. keep the other path narrow or conservative 3. observe several correct activations 4. widen one dimension at a time ## What actually wakes daemons today Today: * event-driven wakes can come from routed GitHub, Linear, and Slack events after repo inference selects a repo with daemon inventory * watch matching is semantic * `schedule` drives scheduled activations * activation mode is derived from `watch` and `schedule`, not authored as its own field For safe rollout, the important distinction is whether the daemon woke because of a signal or because a schedule fired. ## How to verify whether a daemon is working Check the daemon against its own file. For each activation, ask: * Did it wake for the right reason? * Did it follow the daemon’s `purpose`? * Did it perform one or more of its `routines`? * Did it avoid anything in `deny`? * Did it follow the body guidance for decision policy, communication policy, verification, freshness, limits, coordination, and ignore patterns? * Did it run any daemon-internal verification required by its file? * Did it produce work on the right native surface? * Did it do the minimum correct work for this activation? Separate wake context from action scope. `watch` and `schedule` explain why the daemon woke now. They do not expand what the daemon is allowed to do. Permission still comes from the daemon’s `purpose`, `routines`, `deny`, and body guidance. Because there is no dedicated activity page today, human rollout verification usually means reading the daemon’s visible work on GitHub, Slack, and Linear. It should also include checking whether the daemon performed any internal verification its file required before acting. ## A simple iteration loop Use this loop: 1. narrow the daemon file before rollout 2. activate it through the team’s normal rollout workflow 3. observe a small number of live activations 4. inspect the visible outputs 5. decide whether the problem is: * wrong wake * wrong action * missing Limit * missing target boundary or Ignore patterns * missing Coordination rule * missing `deny` 6. edit the daemon file 7. merge or activate the tighter or wider version 8. repeat The main debugging surface is the daemon file itself. `DAEMON.md` is the daemon’s canonical operating brief and primary role policy. When the daemon behaves incorrectly, fix the authored policy and guidance rather than trying to prompt around the problem. ## What to change first when something goes wrong ### If the daemon wakes too often Look first at: * `watch` * `schedule` * target boundaries * Ignore patterns ### If the daemon wakes correctly but is too chatty Look first at: * `routines` * Limits * Communication policy * Coordination ### If the daemon takes actions it should not take Look first at: * `deny` * target boundaries * Decision policy ### If the daemon is too passive Look first at: * whether target boundaries are too narrow * whether `routines` are too weak or vague * whether `deny` rules are over-constraining it ## Widening scope safely Widen one dimension at a time. Examples: * from “only PRs opened by the tester” to “one small team’s PRs” * from tester-only Slack DMs to a small shared channel * from one labeled test PR to one label category * from a sandbox repo to one low-risk production repo area * from one test branch pattern to one broader branch target * from a narrow directory to a broader repo area * from a small activation volume to a larger one Do not widen scope, output audience, routine breadth, and schedule intensity all at once. There is no fixed required number of successful activations defined here. In practice, widen only after several quiet, correct, low-blast-radius activations. Signals that a daemon is still too broad or under-constrained include: * it comments where humans are already actively working * it repeats work another daemon already did * it produces more visible output than the team can review * it touches targets outside the intended early rollout set * it acts instead of stopping, commenting with the blocking reason, or asking for specific human input on ambiguous cases ## Dampening or stopping a noisy daemon If a daemon is producing noise, merge a more restrictive daemon file quickly. Typical dampening moves: * tighten `watch` * narrow target boundaries * add Ignore patterns * add or strengthen `deny` * add or strengthen Limits * add stronger Coordination rules * stop/no-op, comment with the blocking reason, or ask for specific human input instead of acting directly * reduce visible output breadth * route early outputs back to low-blast-radius surfaces For scheduled daemons, removing `schedule` is the normal way to stop future timed activations. In rare stale-state windows, that change may not take effect instantly, so confirm on native surfaces before assuming the schedule path is fully stopped. ## Testing checklist Before rollout or widening, run structural validation in the repository that contains the daemon files: ```bash theme={null} bunx @charlie-labs/daemons validate --all ``` This checks file structure only. It does not prove live daemon behavior, wake routing, integration access, output quality, or any daemon-internal verification the file asks Charlie to perform. Before widening a daemon, confirm: * `bunx @charlie-labs/daemons validate --all` passes * the daemon woke only in the situations you expected * overlapping `watch` entries did not cause duplicate activations for the same underlying signal * the daemon’s visible outputs were easy to review * the daemon followed its own purpose and routines * the daemon respected `deny` and Limits * the daemon respected target boundaries, Coordination, and Ignore patterns * the daemon re-checked current state before acting when state could have changed * the daemon ran any internal verification required by its file * when the daemon no-oped or completed a low-noise action silently, that silence was consistent with the daemon’s communication policy * the daemon did not create more work than the team could absorb * the next widening step is small and deliberate If any of those are not true, tighten the daemon and test again. # Writing and editing DAEMON.md Source: https://docs.charlielabs.ai/daemons/writing-and-editing-daemon-md Create and improve DAEMON.md files that are narrow, explicit, and safe to run repeatedly. **Human readers:** the fastest way to get started with daemons is to work directly with Charlie. **Charlie can help you** suggest where to start and add your first daemon. Use the prompts below to ask Charlie in Slack, GitHub, or Linear. ```markdown Learn about daemons theme={null} Explain what daemons are and how they work. ``` ```markdown Daemon use cases theme={null} What are some use cases for daemons? Which would you recommend starting with? ``` ```markdown Add a daemon theme={null} Open a PR to add a simple daemon to my repo. Explain what the daemon does and why you think it's a good place to start. ``` *** Use this page when Charlie or another agent is creating a new daemon file or improving an existing one. Use [DAEMON.md reference](/daemons/daemon-md-reference) for the exact contract. Use this page to make the file good, not just valid. For a focused PR-review pass before merge, use the [Review Checklist](/daemons/review-checklist). ## The default stance Write the narrowest daemon that can do the job. **Start as simple as possible. New `DAEMON.md` files should normally target 50–100 lines.** Do not try to cover every use case, edge case, and restriction before the daemon ships. Capture the smallest reliable first version, then iterate after real activations, review feedback, and observed failure modes show what the daemon actually needs. A good daemon file is: * narrow * explicit * concise * predictable * easy to review and iterate on Start with: * one purpose * usually 2–3 routines * clear deny guidance * only the body sections that materially improve behavior Do not write a broad, impressive-looking daemon that is hard to trust, and do not pad a first version with speculative future cases. ## Frontmatter vs body Use **frontmatter** for the concise declarative contract: * identity * purpose * wake conditions * core routines * hard prohibitions * schedule Use the **body** for operating guidance that makes behavior more consistent: * decision policy * verification and freshness policy * output format * communication behavior * limits * target-selection details that cannot fit cleanly in frontmatter * priority * thresholds * conventions * coordination and concurrency behavior * ignore patterns * examples Authors set `watch` and/or `schedule`. The runtime derives activation mode from those fields; do not add `activationMode` as a frontmatter field. A daemon must include at least one of `watch` or `schedule`. If something is a stable authored field, it belongs in frontmatter. If something is operating guidance or judgment-shaping prose, it belongs in the body. Do not duplicate `purpose`, `watch`, `routines`, or `deny` in body sections. If a body section only restates frontmatter, delete it or move the hard rule into frontmatter. Hard target boundaries usually belong in `watch`, `routines`, or `deny`. Use the body for nuanced target-selection policy, not for generic restatements of what the daemon is. ### Runtime policy, not setup notes The body should read correctly while the daemon is running. Avoid prose like “replace this with your default branch” or “configure this command before enabling” inside `DAEMON.md`; those are setup instructions, not runtime policy. ## Create mode When creating a new daemon: ### 1. Write the purpose as outcome, not mechanics A strong `purpose` says what the daemon exists to achieve. Good: * “Keeps repository docs current and easy to discover.” Weak: * “Scans for stale markdown files and suggests updates.” The daemon’s purpose should make sense as the role’s job statement. ### 2. Choose the wake model Use `watch` when the daemon should react to discrete events. Write `watch` with concrete event or signal language available when the daemon wakes. If the daemon needs a follow-up query or derived analysis to know whether action is needed, put that check in execution guidance instead of the wake condition. Use `schedule` when the daemon should wake on time and survey what needs attention. Use both only when the same daemon role genuinely needs both immediate reaction and periodic review. A daemon must include at least one of `watch` or `schedule`. ### 3. Write a small number of concrete routines Routines should be concrete, finite operations. Good routines are things you can tell whether the daemon did or did not do. Good: * “propose clearer PR titles and summaries” * “identify missing test evidence in PR descriptions” * “suggest focused follow-up tasks when context is incomplete” Weak: * “help with pull requests” * “improve code quality” * “manage the repo” As a default, start with 2–3 routines. ### 4. Add deny rules for adjacent risks The most important `deny` rules are not random safety slogans. They are the risky actions the daemon might reasonably attempt as a natural extension of its routines. Examples from the authoring guidance: * “Do not merge pull requests” * “Do not approve pull requests on behalf of humans” * “Do not push commits directly to protected branches” * “Do not delete files or directories” If a daemon can plausibly take a risky shortcut, decide explicitly whether to deny it. ### 5. Add body guidance only where it improves behavior The body is not decorative. Use it to make the daemon more predictable. A small daemon does not need every possible section. Add sections when they materially improve consistency, reduce noise, or make outputs easier to review. Good body guidance usually answers questions that frontmatter cannot answer on its own: * when to act and when to stop/no-op * what evidence is enough * what freshness checks are required before writes * what verification the daemon must run before consequential changes * when to comment, react, resolve, hide, edit, push, or stay silent * how to avoid duplicate work with humans or other daemon activations ## Edit mode Editing is not the same as creation. When editing an existing daemon: ### 1. Read before rewriting Inspect the current daemon file first. Preserve: * the daemon’s identity * the intended role * any guidance that is already working Do not rewrite a daemon from scratch unless the role itself is wrong or the file is too weak to repair incrementally. ### 2. Diagnose the failure mode Before changing the file, decide whether the problem is: * the daemon wakes for the wrong things * the daemon wakes correctly but acts too broadly * the daemon lacks enough operating guidance * the daemon is missing limits * the daemon is over-constrained and too passive Different problems require different edits. ### 3. Tighten vague or brittle watch conditions Turn state-based or catch-all watch entries into specific, observable events. Prefer edits like: * “when a pull request is opened” * “when a maintainer comments `/daemon help` in a PR” * “when files matching docs/\*\*/\*.md are changed” Over vague entries like: * “when the repo needs attention” * “when code changes” Keep the daemon’s role the same. Make the wake logic more precise, not broader. Do not make `watch` depend on state that is not available in the event or signal that wakes the daemon. If the daemon needs a follow-up query or derived analysis to know whether action is needed, wake on the closest observable event and inspect that state during execution. Avoid overlapping watch entries that usually describe the same underlying trigger. One inclusive, concrete watch condition is usually easier to route and less likely to create duplicate activations than several broad entries. ### 4. Narrow or split broad routines If one routine covers several jobs, split it. If a routine sounds like an abstract responsibility, rewrite it as a concrete operation. Prefer the smallest set of routines that still captures the daemon’s real job. ### 5. Add missing deny rules Look for risky shortcuts the daemon might naturally attempt as the fastest way to satisfy its routines. Add deny rules for those nearby risks rather than generic safety slogans. ### 6. Reduce noise without changing the daemon’s identity If the daemon is doing the right kind of work but too often, too broadly, or too noisily, do not change the `purpose` first. Instead, tighten the parts that bound behavior: * add `Limits` to control volume or pacing * add target boundaries or `Ignore patterns` to filter surfaces early * add `Coordination` to avoid overlap with humans or other daemon activations This keeps the daemon’s role intact while making repeated activations more trustworthy. ### 7. Prefer targeted improvement over full rewrite Prefer the smallest change that clearly improves behavior. Rewrite only when the file’s role definition is fundamentally wrong or the current file is too inconsistent to repair incrementally. ## How to write strong frontmatter ### `id` `id` must exactly match the daemon ID and path slug. Good: * `pr-check-repair` Bad: * `PR Check Repair` ### `purpose` Write the intended outcome, not the mechanics. Good: * “Keeps repository docs current and easy to discover.” Bad: * “Scans for stale markdown files and suggests updates.” ### `watch` Each watch entry should describe a specific, observable event. Good: * “when a pull request is opened” * “when a maintainer comments `/daemon help` in a PR” * “when files matching docs/\*\*/\*.md are changed” Provider-specific examples should name provider-visible events rather than raw webhook labels. Good: * “A GitHub pull request review is submitted on an open non-draft pull request.” * “A top-level GitHub PR comment is created on a pull request.” * “A GitHub pull request head commit changes on an open non-draft pull request.” * “A GitHub-visible check run, check suite, or commit status fails on a pull request.” * “A Linear issue is created.” * “A Linear issue comment is added on an issue.” * “A Slack message is posted in the named support channel.” * “A Slack thread reply is added in the named support channel.” Weak: * “PR activity happens.” * “pull\_request\_review\.submitted webhook received.” * “when code quality is low” * “when the repo needs attention” * “when code changes” Use watch entries that describe something the system can observe as an event. Watch matching is semantic rather than deterministic rule matching, so concrete observable phrasing is more reliable than vague state-based phrasing. Be specific, but not brittle. Avoid both “wake on everything” and conditions that overfit to one temporary actor, exact phrase, or implementation detail unless that detail is part of the daemon’s durable activation contract. Do not write watch conditions that require data unavailable in the event or signal that wakes the daemon. For example, if a desired state can only be known by querying an API or analyzing repo state, use `watch` for the closest observable event and put the state check in `routines`, `deny`, or body policy. Avoid overlapping watch entries that usually describe the same underlying trigger. Prefer one inclusive observable event over several broad entries that may create duplicate activations. Current watch behavior can use routed GitHub, Linear, and Slack events after routing selects a repo with daemon inventory. For Linear events, write `watch` entries that name observable issue or comment activity and make sure the issue's Linear team maps to the intended repo. For Slack events, name observable channel or thread activity and make sure the relevant Slack workspace maps to the intended repo. ### `routines` Each routine should be a concrete, finite operation. Good: * “propose clearer PR titles and summaries” * “identify missing test evidence in PR descriptions” * “suggest focused follow-up tasks when context is incomplete” Weak: * “help with pull requests” * “improve code quality” * “manage the repo” ### `deny` Write deny rules for the most important nearby risks. If a daemon might reasonably try a risky action because it seems like the fastest path to its goal, decide explicitly whether to deny that action. Deny rules are the right place for hard boundaries: targets the daemon must not touch, actions it must not take, and cases where it must stop/no-op. If author identity, target resource, issue ID, validity, ownership, permissions, or freshness cannot be established, prefer fail-closed behavior unless the daemon explicitly allows best-effort action. ### Activation and execution safety `watch` gets the daemon activated. It does not prove action is safe. Use `routines`, `deny`, and body policy to make the daemon re-check current truth before acting. For mutating daemons, state what must be re-fetched or re-validated immediately before writes, pushes, or external updates. For daemons that push to PR branches, explicitly state force-push policy. Deny force-push by default unless the repo's policy permits rebase-based repair; when allowed, require fresh remote state and `--force-with-lease`. Also state whether fork or cross-repository PR branches are out of scope. ### `schedule` Use `schedule` for timer-based wakes. Schedules use standard five-field cron in UTC. This is for time-based survey or follow-up work, not for describing event conditions. The runtime may derive activation-mode labels from `watch` and `schedule`. Do not write `activationMode` as a frontmatter field. Examples: * `0 9 * * *` — daily at 09:00 UTC * `0 */6 * * *` — every 6 hours * `30 14 * * 1-5` — weekdays at 14:30 UTC ## How to write strong body guidance Use only the sections that materially improve behavior. ### `Decision policy` Use when the daemon needs decision rules, standards, or team opinions about what good looks like. Prefer compact “act when / stop when” rules, allow-lists, thresholds, and action matrices. Use examples to clarify judgment, not as a substitute for policy. Define ambiguous terms once. If the daemon depends on concepts like “valid,” “fixed,” “duplicate,” “straightforward,” “non-human,” or “blocked,” make those terms explicit. ### `Output format` Use when the daemon produces comments, reports, or other structured visible output and you want consistency. ### `Communication policy` Use when the daemon may communicate or mutate visible state. Define exactly when it should comment, react, resolve, hide, edit, push, or stay silent. Separate routine no-ops from comment-worthy cases. No-op silently for stale triggers, already-handled work, unsupported states, missing context, or ambiguity. Comment only when human input is specifically needed or visible action needs explanation. ### `Verification and freshness` Use when the daemon performs consequential writes or relies on mutable external state. State what the daemon must re-fetch or re-validate before acting. State what verification it must run, and what it should do if verification cannot run, fails, or fails for unrelated reasons. ### `Limits` Use when the daemon could otherwise create too much output or work. Limits can control: * batch size * rate * pacing relative to human capacity ### `Target selection` Use when the daemon needs nuanced filtering that cannot fit cleanly in `watch`, `routines`, or `deny`. Prefer domain-specific headings when they are clearer, such as `Candidate discovery`, `Triage items`, `Issue inference`, or `Repair policy`. ### `Priority` Use when several valid targets may compete for the daemon’s attention. ### `Thresholds` Use when numeric or qualitative cutoffs should affect detection or action. ### `Conventions` Use when the team has norms the daemon should follow. ### `Coordination` Use when the daemon might overlap with human work or other daemon activations. Define this daemon’s own boundary. Avoid naming sibling daemons unless another daemon is part of the activation contract or a true authority source. ### `Human authority` Use when human-authored input should govern the daemon’s behavior. Say when human input is a source of truth, and say when human-authored input should not be modified, adjudicated, or acted on automatically. ### `Ignore patterns` Use when specific files, directories, labels, authors, or event patterns should be skipped entirely. ### `Examples` Use when the daemon’s job includes subjective judgment and concrete examples will improve consistency. Examples are secondary to policy. Add them only when they clarify judgment that rules cannot capture. ## What to include only when it matters Not every daemon needs every body section. Add these only when they materially improve behavior: * Add `Limits` when the daemon could otherwise create more work or noise than the team can absorb. * Add `Output format` when the daemon produces comments, reports, or other recurring visible output and consistency matters. * Add `Communication policy` when the daemon may make visible comments or state changes. * Add `Verification and freshness` when the daemon writes, pushes, or updates external state. * Add `Coordination` when overlap with humans or other daemon activations is plausible. * Add `Target selection` or `Ignore patterns` when the daemon listens to a high-volume surface or only part of the repo or workflow is relevant. * Add `Examples` only when the daemon’s job depends on subjective judgment that policy alone does not capture. ## Common mistakes These are the most common daemon-file mistakes: ### Vague watch conditions A watch entry must describe an event, not a general state. ### Brittle watch conditions A watch entry should not depend on data unavailable in the event or signal that wakes the daemon. Use execution-time checks for state that requires a follow-up query or derived analysis. ### Overlapping watch conditions Multiple broad watch entries for the same underlying trigger can cause duplicate activations. Prefer one inclusive watch condition when event families overlap. ### Unbounded routines If you cannot tell whether the daemon completed the routine, the routine is too vague. ### Missing deny rules If a risky nearby action is plausible, decide explicitly whether to deny it. ### Duplicating frontmatter in the body Do not add body sections that only restate `purpose`, `watch`, `routines`, or `deny`. ### Undefined decision terms If a daemon relies on terms like “valid,” “fixed,” “duplicate,” or “straightforward,” define them once. ### Missing freshness or verification policy If a daemon writes, pushes, resolves, edits, or updates external state, say what current state it must re-check and what verification it must run before acting. ### No limits where output can sprawl A daemon without limits can produce more work or noise than the team can absorb. ### Invented frontmatter fields Do not invent fields. Use the authored fields from [DAEMON.md reference](/daemons/daemon-md-reference). ### Treating body headings like schema Headings such as `Decision policy`, `Limits`, or `Target selection` belong in the markdown body, not as new frontmatter fields. ### Generic filler in the body If a section does not change what the daemon will actually do, tighten it or remove it. ### Stale terminology after edits After changing policy, search for old daemon names, old terms, duplicate constraints, and contradictory allow/deny language. ## Final consistency scan Before merging a daemon file, scan it once from top to bottom and check: * Frontmatter contains the durable contract, and the body does not repeat it. * `watch` describes observable wake events, not derived state that must be queried during execution. * Hard boundaries are in `deny`, `watch`, or `routines`; nuanced selection policy is in the body. * Decision terms are defined once and used consistently. * Mutating behavior has freshness and verification requirements. * Communication behavior says when to comment, react, resolve, hide, edit, push, or stay silent. * Stop/no-op behavior is explicit for ambiguous identity, target, ownership, permissions, freshness, or validity. * The file has no stale section names, duplicate constraints, or contradictory allow/deny language left over from earlier edits. ## Critique rubric Use this rubric when reviewing a draft daemon file. ### Purpose * Is the purpose written as outcome, not mechanics? * Is the role narrow enough to explain in one sentence? ### Wake logic * Are watch conditions actual events? * Are watch conditions specific without being brittle? * Do watch conditions avoid relying on unavailable derived state? * Do overlapping watch entries risk duplicate activations? * Does the schedule serve a real time-based need? * Is the daemon using both `watch` and `schedule` only when both are justified? * If the daemon is noisy, can the wake logic be made more specific without changing the role? ### Routines * Are routines concrete and finite? * Would a human be able to tell whether the daemon did them? * Does each routine describe one kind of operation, or should any be split? ### Constraints * Are the main adjacent risks denied? * Are limits present when the daemon could create noise? * Would target-selection policy, coordination, or ignore patterns make the daemon more predictable? * Does the daemon fail closed on important ambiguity? ### Body guidance * Does the body add real behavioral guidance? * Are the sections specific, or are they generic filler? * Are ambiguous terms defined? * Are freshness, verification, communication, and concurrency rules present when the daemon needs them? * Does the file avoid coupling to named sibling daemons unless they are a true authority or activation source? ### Overall * Is this the narrowest useful daemon? * If it is noisy, can you fix that with tighter watch logic, routines, or body guidance before changing the purpose? * Would you trust this file to be activated repeatedly? * Has the file been scanned for stale terms and duplicated or contradictory rules? If the answer is “no” to any of those, edit the file before rollout. ## Scaffold from an example with the CLI When an existing example is close to the role you need, use the daemon CLI to inspect it, preview the scaffold, then write the draft files. ```bash theme={null} bunx @charlie-labs/daemons show pr-metadata bunx @charlie-labs/daemons add pr-metadata --dry-run bunx @charlie-labs/daemons add pr-metadata ``` `show` surfaces the example’s readiness, integrations, support files, and required adaptation notes. Review those notes before rollout; examples are starting patterns, not turnkey policy. `add --dry-run` previews the files without writing them. `add` writes the scaffold under `.agents/daemons//`, including the example `DAEMON.md` and any catalog-listed support files. Generated files are drafts. Adapt the daemon to the repository’s real role, constraints, integrations, output surfaces, and rollout plan before relying on it. Scaffolding does not activate the daemon. The daemon becomes eligible for live activations only after the change is merged to the repository default branch and Charlie ingests that merged version. For reproducible scaffolding, pass the same `--ref ` to `show` and `add` so browsing and generated files come from the same catalog snapshot. ## How to use examples while writing or editing Start with the nearest example daemon from the [examples repo README](https://github.com/charlie-labs/daemons/blob/master/README.md). Use examples to copy: * structure * level of specificity * the kind of constraints that belong with a daemon role Do not copy: * irrelevant routines * irrelevant deny rules * irrelevant scope or limits * team-specific conventions that do not apply here A good example gives you the right shape. It does not remove the need to adapt the daemon to the repo’s real role. # Docs, but Faster Source: https://docs.charlielabs.ai/docs-but-faster These are the fastest ways to learn about Charlie: If your organization has Charlie installed, ask @CharlieHelps in GitHub or ask @Charlie in a connected Slack or Linear workspace. Charlie can also help check or draft daemon `watch` wording. Use the AI-enabled search bar at the top of this docs site. Paste this LLM‑friendly reference into your model of choice: (click here). GitHub uses two identities: `CharlieCreates` is the GitHub App for repo access and actions, while `CharlieHelps` is the GitHub user for mentions, review requests, assignments, and autocomplete. Linear and Slack use Charlie’s app identity, so mentions usually look like `@Charlie`. See GitHub App and user for details. # Environment setup Source: https://docs.charlielabs.ai/environment-setup Prepare Charlie devboxes for repo-specific dependencies and system packages. Charlie works best when your repo can set up its own development environment from a fresh clone. Put setup where your repo already runs after dependency installation. For JavaScript and TypeScript repos, that usually means `postinstall`. Gate Charlie-only work with `IS_CHARLIE=1`, store secrets in dashboard repository environment variables, and use `AGENTS.md` to tell Charlie how to use the environment. Use this setup path for build, test, and tooling dependencies that can be installed noninteractively. Running services, such as Docker Compose stacks, background processes, or databases, should be documented in `AGENTS.md` and handled as a separate workflow. ## What Charlie sets up automatically Charlie creates repo-specific devbox blueprints so new runs start from a prepared environment instead of a blank machine. For most repos, Charlie will: * Clone the repository into the devbox. * Provide common tools and package categories: Git, Bash, Python, Node package managers, build tools such as `make`, `cmake`, and `pkg-config`, CLIs such as `jq`, `ripgrep`, `curl`, and `gh`, `mise`, and native headers used by frequent Node/image/database-client packages. * Detect JavaScript package managers and run dependency installation with the repo's normal lifecycle scripts. * Inject configured repository environment variables from the Charlie dashboard. * Set `IS_CHARLIE=1` during Charlie runs. Charlie does not try to guess every apt package your repo might need. If your tests, builds, or tools need extra system packages after dependencies install, declare them in your repo setup. ## Recommended pattern For JavaScript and TypeScript repos, use this shape for setup that can run after package-manager dependency installation has completed: Keep `package.json` small and route the real work to a script. Do not use this path for apt packages that are required by dependency install scripts or native addon builds; `postinstall` runs too late for those. ```json theme={null} { "scripts": { "postinstall": "bash scripts/setup-charlie-env.sh" } } ``` The script should exit quickly outside Charlie unless you intentionally support local use. ```bash theme={null} #!/usr/bin/env bash set -euo pipefail if [[ "${IS_CHARLIE:-}" != "1" ]]; then exit 0 fi sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ libpq-dev \ pkg-config ``` Design setup so it is safe to run more than once. * Use `--no-install-recommends` for apt packages. * Pass `DEBIAN_FRONTEND=noninteractive` on each `sudo apt-get` command. * Prefer commands that no-op when packages already exist. * Do not prompt for input. * Do not print secrets. ## Install system dependencies Use real apt commands for packages that must exist before tests or build tools run, as long as those packages are not required during dependency installation itself. Example: native database client headers and build metadata: ```bash theme={null} sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ libpq-dev \ pkg-config ``` Example: image processing dependencies used by common native modules: ```bash theme={null} sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ libvips-dev \ libcairo2-dev \ libpango1.0-dev ``` Example: command-line tools needed by tests: ```bash theme={null} sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ poppler-utils \ graphviz ``` Keep the list focused. If Charlie already has a tool installed, you do not need to reinstall it. If a package is needed while `bun install`, `pnpm install`, `yarn install`, or `npm install` is still running, do not rely on `postinstall`; ask Charlie for a pre-dependency-install blueprint update instead. If you want one setup script to work in Charlie and on developer laptops, consider using `mise` for user-level tools and runtimes. Charlie devboxes include `mise`, so a guarded setup script can run `mise install` for repo tools while keeping apt-only work behind the `IS_CHARLIE=1` guard or a separate opt-in local path. ## Non-JS repos `postinstall` is the main recipe for work that can happen after JavaScript dependency installation. Charlie runs package-manager installs first, so dependency install scripts and native addon builds may fail before the root `postinstall` script can install missing system packages. For non-JS repos, use the closest equivalent your team already trusts: * `make setup-charlie` * `just setup-charlie` * `scripts/setup-charlie-env.sh` * `mise install` plus a documented setup task Then document the command in `AGENTS.md` so Charlie knows to run it when preparing the repo or debugging environment failures. ## Tell Charlie how to use the environment Use `AGENTS.md` for durable instructions about setup, verification, and known caveats. ```md theme={null} ## Charlie environment - Repo setup that runs after dependency installation is handled by `postinstall`, which calls `scripts/setup-charlie-env.sh`. - The setup script installs Charlie-only system packages when `IS_CHARLIE=1`. - If tests fail because a system package is missing after dependencies are installed, update the setup script instead of installing packages ad hoc. - If dependency installation itself fails because a native package is missing, ask Charlie for a pre-dependency-install blueprint update. - Required secrets are configured as Charlie dashboard repository environment variables. Do not print them in logs. - Validate environment changes with `bun test` and the affected package checks. ``` Keep this short and operational. `AGENTS.md` should tell Charlie what to do, not repeat every package in the setup script. ## Secrets and environment variables Use dashboard repository environment variables for non-public keys, tokens, and runtime config needed during Charlie runs. Sign in to the Charlie dashboard, select the relevant organization and repository, then open **Secrets** (or **Manage secrets**) to configure them. Good uses include: * Package registry tokens such as `NPM_TOKEN`. * API keys for test doubles or sandbox services. * Runtime config used by build or verification commands. Do not commit secrets to the repo, echo them from setup scripts, or include them in generated logs. If a setup command needs a secret, read it from the environment and fail with a generic message when it is missing. ## How blueprints work Blueprints are repo-specific prepared devbox images. They are similar to Docker images: Charlie builds them from your repo setup so future devboxes can start faster with dependencies already present. Charlie checks blueprints on repository pushes and rebuilds them when the existing blueprint is stale. Changes may not apply immediately, and existing devboxes may keep using the environment they already have. If you need a setup change available right away, contact Charlie and ask for an on-demand blueprint update. ## Troubleshooting ### `apt-get` prompts or hangs Pass `DEBIAN_FRONTEND=noninteractive` on the `sudo apt-get` command and use `-y`: ```bash theme={null} sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ``` ### A native dependency fails during package install `postinstall` cannot repair apt packages required by dependency install scripts or native addon builds, because the package-manager install may fail before `postinstall` runs. Ask Charlie for a pre-dependency-install blueprint update for those packages. ### Package install works once, then fails later Make the script idempotent. Check for files, directories, or commands before creating or installing them, and prefer package manager commands that tolerate already-installed packages. ### A package is missing in Charlie but installed locally If the package is needed after dependencies install, add it to the repo setup script and commit the change. If it is needed while dependencies install, ask Charlie for a pre-dependency-install blueprint update. Local machine state is not part of the blueprint unless the repo can recreate it. ### A change is not visible in a new Charlie run Blueprint updates may lag. Ask Charlie for an on-demand blueprint update if the new package is blocking work. ### Setup needs a running service Leave it out of this page's setup path for now. Document the need in `AGENTS.md` and ask Charlie how to handle that workflow separately. ## Complete example `package.json`: ```json theme={null} { "scripts": { "postinstall": "bash scripts/setup-charlie-env.sh" } } ``` `scripts/setup-charlie-env.sh`: ```bash theme={null} #!/usr/bin/env bash set -euo pipefail if [[ "${IS_CHARLIE:-}" != "1" ]]; then exit 0 fi sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ libpq-dev \ pkg-config \ poppler-utils if command -v mise >/dev/null 2>&1 && [[ -f .mise.toml ]]; then mise trust .mise.toml -y mise install fi ``` `AGENTS.md`: ```md theme={null} ## Charlie environment - Environment setup that can run after dependency installation runs from `postinstall` via `scripts/setup-charlie-env.sh`. - Charlie-only setup is guarded by `IS_CHARLIE=1`. - Repository secrets come from Charlie dashboard environment variables. Never print them. - If tests or builds fail after dependency installation because a package is missing, update `scripts/setup-charlie-env.sh` and re-run the affected verification command. - If dependency installation itself fails because a native package is missing, ask Charlie for a pre-dependency-install blueprint update. ``` # FAQ Source: https://docs.charlielabs.ai/faq Common questions about Charlie, including daemon behavior. ## Daemons FAQ A daemon is a repo-defined operating role for recurring work. It is not a long-running OS process. Each daemon is defined in a file at: .agents/daemons/\/DAEMON.md watch wakes a daemon from matching events. schedule wakes a daemon on a cron timetable. A daemon can use either one or both. Daemons can wake from scheduled cron wakes through schedule, plus routed GitHub, Linear, and Slack events through watch. Linear event wakes require the Linear integration to be connected and the issue's Linear team mapped to the intended repo. Slack event wakes require the Slack integration to be connected and the Slack workspace mapped to the intended repo. Cron schedules are evaluated in UTC. Yes. Activations are bounded runs with explicit start/end, tool limits, and normal permission constraints. Daemons can use prior activation history as context, but they do not run as a permanently active process. Use only the canonical fields: id, purpose, watch, routines, deny, and schedule. Do not invent alternate top-level schema keys for activation mode. ## General FAQ Charlie is strongest in TypeScript and supports many common languages/frameworks used in modern repositories. Small and medium PRs are typically reviewed in minutes. Complex PRs can take longer when deeper validation is needed. Check installation scope, invocation method, and permissions first. Then use the [Troubleshooting](/troubleshooting) checklist. Yes. Charlie is useful for both human-authored and agent-authored pull requests. Charlie can analyze images attached in supported surfaces and use them as task context. Email [support@charlielabs.ai](mailto:support@charlielabs.ai). # How It Works Source: https://docs.charlielabs.ai/how-it-works Charlie’s runtime model, execution flow, and operating boundaries. To learn more about how daemons work, please read [How Daemons Work](https://charlielabs.ai/how-it-works). To learn more about how Charlie works generally, please read about [CAOS, the Coding Agent Operating System](https://charlielabs.ai/blog/charlie-v2-introducing-the-coding-agent-operating-system-caos/). ## Multi-surface wake model Charlie can start work from routed events on the systems your team already uses: * GitHub events such as mentions, review requests, assignments, and PR activity * Linear events such as issue creation, issue comments of any kind on mapped issues, issue mentions, and issues assigned to Charlie * Slack events such as mentions, thread replies, channel messages, and DMs * daemon `schedule` entries for cron-based wakes For daemon `watch` conditions, GitHub events route through the repo-scoped GitHub App installation. Linear events require a connected Linear workspace and the event issue's Linear team mapped to the repo where the daemon lives. Slack events require a connected Slack workspace mapped to that repo. Use [Daemons](/daemons) for wake model details and [Integrations](/integrations) for setup. Charlie run lifecycle visual overview # Installation Source: https://docs.charlielabs.ai/installation Set up Charlie with GitHub, then connect optional integrations. Charlie has two offerings: * **Agents** for on-demand work (mentions, assignments, review requests) * **Daemons** for scheduled or watch-based automation To run Charlie, complete the required setup below: sign up with GitHub and install/scope the `CharlieCreates` GitHub App on the repositories Charlie should access. ## Required setup Go to dash.charlielabs.ai/signup and select **Sign up with GitHub** to authenticate the GitHub account that will install and manage Charlie. Install CharlieCreates and scope access to the exact repositories where Charlie should run. You can start narrow and add more repositories later. ## Recommended GitHub user setup Inviting CharlieHelps is optional, but recommended when you want teammates to mention Charlie, request Charlie’s review, assign work to Charlie in GitHub, or see Charlie in GitHub autocomplete. `CharlieCreates` remains the required GitHub App that grants repo-scoped access and powers most GitHub actions. `CharlieHelps` is the GitHub user that makes GitHub’s people-oriented UI work. Repo-scoped app actions and app-backed or scheduled daemon workflows are not blocked on the user invite. Many teams invite both; see GitHub App and user for the comparison. Using Charlie on public/open-source repositories? Review Open Source first, then follow your org’s security policy for GitHub App scope and token handling. ## Optional but recommended integrations You can use Charlie with GitHub only, but most teams also connect: * [Linear](/integrations/linear) * [Slack](/integrations/slack) * [Sentry](/integrations/sentry) * [Vercel](/integrations/vercel) See the [Integrations](/integrations) hub for setup paths. If you want Linear events to wake daemon `watch` conditions, connect Linear and map the relevant Linear team(s) to the repo where the daemon lives. For Slack event wakes, connect Slack and map the Slack workspace to that repo. GitHub-only setup supports GitHub-routed events and scheduled daemon wakes, but not Linear or Slack event wakes. ## Daemons setup If you want scheduled or watch-driven automation, continue to [Daemons](/daemons). # GitHub Integration Source: https://docs.charlielabs.ai/integrations/github Connect GitHub so Charlie can review PRs, open PRs, and keep Linear and Slack in sync. Connecting GitHub is required for Charlie to operate. This core integration gives Charlie access to your codebase and development workflow—enabling him to review code, push commits, create pull requests, and collaborate in your repository just like a fellow developer. Charlie uses two GitHub identities: `CharlieCreates`, the GitHub App and primary repo access/action path for repository-scoped work, and `CharlieHelps`, the GitHub user for people-oriented GitHub UI surfaces like mentions, PR review requests, assignments, and autocomplete. See [GitHub App and user](/integrations/github-identities) for the full comparison. ## What Charlie can do With GitHub connected, Charlie works directly in your repositories and pull requests: * **Review and improve code changes.** Charlie automatically reviews pull requests (especially when they’re marked “Ready for Review”) and provides detailed feedback. Mention `@CharlieHelps, review this PR` or assign him the pull request — he will analyze the diff and comment with findings on potential bugs, performance issues, and best practices. * **Implement code changes on demand.** Assign Charlie to a GitHub issue or ask `@CharlieHelps, open a PR to fix this` — he will create a new branch, commit the changes, and open a pull request that addresses the issue. All commits and the PR will reference the relevant issue or task for traceability. * **Brainstorm and plan solutions.** In an issue or PR comment, ask Charlie for an implementation plan (for example, `@CharlieHelps, how should we fix this?`). He’ll outline a step-by-step solution with code snippets, covering edge cases and validation. * **Answer code questions in context.** Need an explanation of a piece of code or history? Mention Charlie in a comment (e.g. `@CharlieHelps, explain what this function does`) and he’ll pull context from the repository to provide a clear answer with references to the relevant files or commits. * **Keep tasks and code in sync.** Charlie automatically links pull requests and commit messages to related issues (or Linear tickets if you use Linear). This ensures nothing falls through the cracks — every PR Charlie opens is tied to a tracking issue, and he checks that all requirements are met during his code review. ## Pull request reviews Marking a PR as "Ready for review" or assigning the PR to `@CharlieHelps` will initiate a PR review. * Inline review comments (on a specific diff line): Charlie only acts if the comment mentions `@CharlieHelps`. If the inline comments are part of a pending (unsubmitted) review, Charlie will not see them until you click 'Submit review'. * Submitted multi-comment reviews: When you submit the review, Charlie will act if the review body or any of its inline comments mention `@CharlieHelps`. * Request changes behavior: * On PRs opened by Charlie: submitting a review with Request changes triggers Charlie to make edits even without a mention. * On PRs opened by humans: Request changes does not trigger Charlie. Mention `@CharlieHelps`, request a review from `@CharlieHelps`, or assign the PR to `@CharlieHelps` instead. Request changes is only actionable on PRs opened by Charlie. ## Working with Charlie in GitHub Issues Charlie is fully integrated into the GitHub Issues workflow. You can assign work, request implementation plans, or ask technical questions—without leaving GitHub. Just mention `@CharlieHelps` in an issue (in the initial description when you create it) or comment, and he’ll handle the rest. ### Opening a Pull Request from an Issue Charlie can take an issue from idea to implementation: * **Assign the issue to Charlie.** In the GitHub issue, assign @CharlieHelps as the assignee. Charlie will immediately start working on the issue, using the issue title and description as his primary specification. * **Request a PR directly from an issue comment.** In any comment, mention Charlie with a clear instruction. For example: `@CharlieHelps, open a PR to fix this.` — Charlie will create a new branch, implement the fix, and open a pull request referencing the issue. * **Link Sentry issues for deeper debugging.** If you have [Sentry](/integrations/sentry) connected, simply link a Sentry issue in your GitHub issue or PR description. Charlie will automatically pull in stack traces and error context from Sentry to better diagnose and resolve the problem. * **Track progress in real time.** Charlie posts a status comment when he starts, and keeps it updated as he works. * **Mention Charlie when creating the issue.** In the GitHub issue, mention @CharlieHelps when creating the issue and Charlie will immediately start working on the issue, using the issue title and description as his primary specification. ### Communicating and Collaborating Charlie supports a wide range of requests and questions inside issues: * **Request a technical plan.** Ask Charlie for a detailed implementation plan or fix proposal `@CharlieHelps, outline a step-by-step plan to solve this issue.` * **Research and brainstorm solutions.** Have Charlie gather external resources or best practices: `@CharlieHelps, research approaches to this problem and include links to relevant documentation.` * **Get instant answers.** Ask Charlie to explain code, dependencies, or past changes related to the issue: `@CharlieHelps, explain the impact of implementing this issue.` * **Keep everything transparent.** Every action and response Charlie takes is posted directly in the issue, so your team stays in the loop. Charlie’s responses in GitHub Issues are always context-aware—grounded in your codebase, change history, and issue comments. ## Quick Setup 1. **Sign up and complete onboarding** Go to [Installation](/installation), create your account, and follow the onboarding steps. 2. **Install the GitHub App** Install `CharlieCreates` on the repositories where Charlie should review PRs, open PRs, push commits, or respond to GitHub events. 3. **Invite the GitHub user when you use mention, review, or assignment workflows** Add `@CharlieHelps` to your GitHub repo or organization so teammates can mention Charlie, request reviews, and assign work. See [GitHub App and user](/integrations/github-identities) for why many teams do both. ## Troubleshooting If something doesn't work as expected: * **Charlie isn't responding on PRs** – Verify the **CharlieCreates** GitHub App is installed and enabled for the repository. * **Can't mention @CharlieHelps** – Make sure `@CharlieHelps` has been invited to the repo (or is a member of the organization). If invites are delayed due to org policies, contact support. * **Charlie can't push commits** – Ensure `CharlieCreates` has repository access and the target branch allows the action, or ask Charlie to open a PR from a new branch. For the difference between the app and user, see [GitHub App and user](/integrations/github-identities). For more help, see the general Troubleshooting guide at [troubleshooting](/troubleshooting). # GitHub App and User Source: https://docs.charlielabs.ai/integrations/github-identities Understand the difference between CharlieCreates and CharlieHelps on GitHub. Charlie shows up in GitHub through two identities: * `CharlieCreates` is the GitHub App. It is Charlie’s primary GitHub authentication and action path for repository-scoped work. * `CharlieHelps` is the GitHub user. It supports GitHub UI workflows that expect a user account: mentions, PR review requests, assignments, and autocomplete. Most teams use both. Install `CharlieCreates` on the repositories where Charlie should work, and invite `CharlieHelps` when you want people to interact with Charlie through GitHub’s mention, review request, assignment, and autocomplete UI. ## Comparison | Question | `CharlieCreates` | `CharlieHelps` | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Identity type | GitHub App | GitHub user account | | Where you see it | GitHub App installation, repository/org app settings, and app-authorized activity | `@CharlieHelps` mentions, PR review-request picker, assignee picker, and autocomplete | | What it is used for | Primary auth and action path for repo access, webhooks, reading code, pushing commits, and opening/updating PRs | Human-facing GitHub UI compatibility for mentions, PR review requests, assignments, and autocomplete | | Does it grant repo access? | Yes. The app installation scopes which repositories Charlie can access and what actions Charlie can take. | No, not for Charlie’s repository-scoped execution. Inviting the user makes GitHub UI workflows available; the app installation remains the repo access path. | | What breaks if it is missing? | Charlie may not receive GitHub events and cannot reliably read repos, push commits, open PRs, or review code in that repository. | People may not be able to mention Charlie, request Charlie’s review, assign issues/PRs to Charlie, or find Charlie in GitHub autocomplete. | ## Why you may be asked to do both GitHub Apps and GitHub users solve different setup problems: * The GitHub App is the right place to grant scoped repository access. It lets your team decide exactly which repositories Charlie can access and is the primary path Charlie uses to read code, push commits, open pull requests, and respond to GitHub events. * The GitHub user makes Charlie work in GitHub surfaces that are built around people: `@` mentions, assignees, PR review requests, and autocomplete. If support or onboarding asks you to install `CharlieCreates` and invite `CharlieHelps`, it is because the workflow needs both the repo-scoped app permission path and the user-shaped GitHub UI path. Inviting `CharlieHelps` does not replace installing `CharlieCreates` on the repositories where Charlie should operate. ## Setup guidance * Install `CharlieCreates` on every repository where Charlie should review PRs, open PRs, push commits, or respond to GitHub-routed events. * Invite `CharlieHelps` when your team wants to mention Charlie, request Charlie’s review, assign issues or PRs to Charlie, or find Charlie in GitHub autocomplete. * If Charlie cannot access or change a repository, check the `CharlieCreates` app installation first. * If people cannot mention, assign, or request a review from Charlie, check that `CharlieHelps` is available in the repository or organization. For end-to-end setup, see [Installation](/installation). For trigger and response issues, see [Troubleshooting](/troubleshooting). # Integrations Source: https://docs.charlielabs.ai/integrations/index Connect Charlie directly to tools or provide environment variables via the dashboard. There are two ways to extend what Charlie can access: ## 1) Direct integrations Connect the platforms Charlie should read from or write to: * [GitHub](/integrations/github) * [Linear](/integrations/linear) * [Slack](/integrations/slack) * [Sentry](/integrations/sentry) * [Vercel](/integrations/vercel) GitHub, Linear, and Slack are not only context and write surfaces. GitHub-routed events use the repo-scoped GitHub App installation; Linear routed events require a connected Linear workspace and the event issue's Linear team mapped to the right repo; Slack routed events require a connected Slack workspace mapped to the right repo. Use `schedule` for cron-based daemon wakes. ## 2) Repository environment variables Use the dashboard to define per-repository environment variables for build/test/tooling workflows: * Dashboard: dash.charlielabs.ai * Sign in, select the relevant organization and repository, then open **Secrets** to configure variables Use this for non-public keys, tokens, and runtime config needed during Charlie runs. ### Conditional setup for Charlie runs If your repo needs different setup when Charlie is running—for example, during blueprint, devbox, build, test, or tooling scripts—gate that branch with an environment variable such as `IS_CHARLIE=1`. For example, your script can check `IS_CHARLIE` before running Charlie-specific setup, while keeping secrets and runtime configuration in repository environment variables. For the full recipe, see [Environment setup](/environment-setup). # Linear Integration Source: https://docs.charlielabs.ai/integrations/linear Linking Linear workspaces allows Charlie to open PRs, respond to comments, and more directly from your Linear workspace. ## What Charlie can do Once connected, Charlie will be able to: * **Respond in-thread with answers and code.** Ask **@Charlie** follow-up questions or clarifications right on the issue. * **Enrich the ticket with deeper context.** `@Charlie, enrich this issue` pulls stack traces, touched files, recent commits, and related PRs. * **Draft a ready-made implementation plan.** `@Charlie, write an implementation plan` returns a step-by-step roadmap with code changes, tests, and rollout notes. * **Open a pull-request from the issue.** Mention `@Charlie, open a PR for this` **or assign the issue to him**—he spins up a branch, pushes commits, and opens a PR that references the ticket. * **Keep tracking in lockstep.** Commits, PRs, and issue states stay linked automatically, and Charlie surfaces missing requirements when reviewing the PR. * **Understand your team’s priorities.** Has a high‑level understanding of the initiatives and projects that are in flight. ## Daemons and Linear events After you connect a Linear workspace, issue events can wake daemon `watch` conditions when the issue's Linear team is mapped to the repo. Use this when issue hygiene should happen from Linear activity, not only when someone explicitly asks Charlie to help. Supported routed Linear event families include: * issue creation (`Issue.create`) * issue mentions * issue comments * issues assigned to Charlie Project and initiative activity comments are not generally supported routed daemon wakes yet. Issue updates, status changes, label changes, and arbitrary assignment changes are also not currently routed daemon wakes. Linear event wakes require the Linear integration to be connected and the issue's Linear team to be mapped to the intended repo. Mentions and assignment wakes are useful for direct asks. For daemons, prefer passive issue-hygiene workflows that start from issue creation, issue comments, or scheduled surveys without requiring someone to invoke Charlie. Good daemon patterns for Linear include: * triaging newly created issues into labels, owners, or reproduction requests * reviewing new issue comments for blockers, reproduction details, ownership changes, or priority changes * asking for missing details when an issue does not include enough context to act safely * keeping follow-up hygiene current by finding stale asks, unclear owners, or mismatched linked PR state Use provider-visible `watch` wording for issue-created or comment-created workflows, for example: ```yaml theme={null} watch: - A Linear issue is created. - A Linear issue comment is added on an issue. ``` For passive hygiene that is not tied to one creation event, use `schedule` and inspect Linear state during execution: ```yaml theme={null} schedule: "0 16 * * 1-5" ``` ## Quick Setup Follow these steps to connect your Linear workspace with Charlie: Go to [dash.charlielabs.ai](https://dash.charlielabs.ai/) and sign in. Select your organization, then open **Integrations**. linear-dashboard Click **Connect Linear** to initiate the integration process. Follow the Linear OAuth connection flow to authorize Charlie to access your Linear workspace. After successfully linking your Linear workspace, you will be redirected back to the Charlie dashboard. Open the relevant repository, select **Integration defaults**, then choose the Linear team to use for that repository by default. OAuth is workspace-scoped; repository routing is team-specific. connect-linear-team # Sentry Integration Source: https://docs.charlielabs.ai/integrations/sentry Connecting Sentry allows Charlie to access issues and traces directly, enabling faster debugging and streamlined issue resolution. ## What Charlie can do Charlie doesn’t just listen for Sentry webhooks—he actively digs into any Sentry trace he sees in Linear, GitHub, or Slack: * **Inspect any Sentry trace in context.** Mention **@Charlie** on a Linear issue, GitHub issue/PR, or Slack message with a Sentry link and he fetches the stack trace, culprit commits, and frequency data. * **Enrich the bug report automatically.** Charlie attaches that Sentry context back to the Linear ticket so the whole story sits in one place. * **Generate a fix plan.** `@Charlie, draft a fix plan` outlines code edits, tests, and rollout steps ready for review. * **Open a PR and ship the patch.** Approve the plan or say `@Charlie, open the PR` and he spins up a branch, commits the fix, and opens a PR linked to both Linear and Sentry. ## Quick Setup Follow these steps to connect your Sentry organization with Charlie: Go to [dash.charlielabs.ai](https://dash.charlielabs.ai/) and sign in. Select your organization, then open **Integrations**. sentry-dashboard In the Sentry integration form, enter the following values: 1. **Organization slug**: Enter the slug for the Sentry organization Charlie should connect. 2. **Sentry User Auth Token**: Paste the actual Sentry User Auth Token with at least **Read** permissions. The dashboard labels this field **Token reference**, but it sends the value as the token itself; do not enter a secret name or reference. This value is hidden while you type. 3. **Connect Sentry**: Click **Connect Sentry** to validate the token and connect the selected Sentry organization. Get a Sentry User Auth Token from [https://sentry.io/settings/account/api/auth-tokens](https://sentry.io/settings/account/api/auth-tokens) if you do not already have one. Paste that token itself into the field, despite its **Token reference** label. The v2 dashboard validates the token against the organization slug in this form; it does not use a separate organization dropdown or **Save** step. Your Sentry organization is connected when the dashboard confirms that Sentry was connected. ## Troubleshooting If you encounter issues during setup: * **Token validation fails**: Ensure your token is valid and has at least **Read** permissions * **The organization is not visible for this token**: Verify the organization slug and that the token can access that Sentry organization * **Connection issues**: Check that your Sentry organization is accessible # Slack Integration Source: https://docs.charlielabs.ai/integrations/slack Connecting Slack lets Charlie turn threads into actionable Linear tickets, surface git & Sentry context, and ship fixes—all without leaving the thread. ## What Charlie can do With Slack connected, Charlie becomes a teammate in every channel: * **Capture a bug or task as a Linear ticket.** Mention **@Charlie** (e.g., `@Charlie, create a Linear issue with this bug`) and he creates the ticket with the full conversation. * **Pull rich context to understand the problem.** Ask `@Charlie, did we change anything before _X_ that caused this?` or drop a Sentry link—Charlie surfaces relevant commits, stack traces, and root-cause details. * **Brainstorm and propose a fix plan.** `@Charlie, how should we fix this?` delivers approaches, edge cases, and sample code blocks. * **Open a PR straight from chat.** `@Charlie, open a PR to fix this` spins up a branch, commits the patch, and posts the GitHub PR back into the thread. * **Summarize the discussion.** `@Charlie, summary please` condenses the thread into a crisp recap with action items and owners. ## Daemons and Slack events Connected Slack workspaces can also wake daemon `watch` conditions. Use this when useful work starts in Slack and should be handled as a repeatable operating role. Supported routed Slack event families include: * mentions and thread replies * broader channel messages * DMs Slack event wakes require the Slack integration to be connected and the Slack workspace mapping to route Slack activity to the intended repo. Channel constraints are not integration mappings; broad Slack message wakes should be narrowed to intentional channels in daemon `watch` wording or body policy. Good daemon patterns for Slack include: * triaging bug reports or support requests that appear in a shared channel * summarizing a noisy thread into next actions or a Linear issue * producing recurring support summaries or channel reports * keeping Slack-to-issue handoffs clean by filing, linking, and following up on the right issue Use provider-visible `watch` wording, for example: ```yaml theme={null} watch: - A Slack message in the named support channel reports a bug for this repo. - A Slack thread reply is added in the named incident channel. - A Slack message mentions Charlie in the named support channel. - A Slack DM asks Charlie to summarize or file a repo-related issue. ``` ## Quick Setup Follow these steps to connect your Slack workspace with Charlie: Go to [dash.charlielabs.ai](https://dash.charlielabs.ai/) and sign in. Select your organization, then open **Integrations**. slack-dashboard Click **Connect Slack** to start the integration process. Follow the Slack OAuth flow to authorize Charlie for your workspace. After authorizing, you'll be redirected back to the Charlie dashboard. Open the relevant repository, select **Integration defaults**, then choose the Slack workspace to use for that repository by default. connect-slack-team # Vercel Integration Source: https://docs.charlielabs.ai/integrations/vercel Charlie ships via Vercel previews and production deploys out of the box - zero extra seats, tokens, or configuration. ## What Charlie can do * **Automatic preview URLs** - Every branch Charlie opens spins up a Vercel preview so you can click, test, and iterate instantly. * **Hands-free production deploys** - Merge the PR and Vercel ships to prod; Charlie never needs to join your Vercel team. * **One seat, one flow** - Charlie acts only through GitHub, so your Vercel billing and permissions stay exactly as they are. * **Tighter feedback loop** - Review the code, open the preview, ship the fix - all in one pass. ## Quick Setup Good news - there is nothing to configure. ### Ensure the Vercel GitHub App is installed If your repository already has the [Vercel GitHub App](https://github.com/apps/vercel) installed you are done - Charlie will automatically trigger builds and deployments whenever he pushes commits or opens a PR. No API tokens, seats, or additional permissions required. vercel-charlie # Open Source Source: https://docs.charlielabs.ai/open-source How to use Charlie on public repositories with maintainer-first controls. Charlie works on public repositories, but open-source usage has stricter safety controls than private repo usage. ## Maintainer-only invocation model In maintainer repositories, Charlie only accepts invocations that are safely attributable to maintainers. That means: * maintainers can invoke Charlie in maintainer repo context, * outside collaborators cannot invoke Charlie with maintainer privileges, * untrusted or ambiguous trigger paths are intentionally conservative. ## Scope and leakage risk Public + private context mixing can leak information across surfaces if scope is too broad. Recommended defaults: * limit the GitHub App to only the repositories where Charlie is needed, * avoid broad org-wide installs unless required, * keep sensitive private repositories out of the same install scope when possible. ## External collaborator behavior External contributors cannot invoke Charlie in maintainer repo context. If they want Charlie support, they should use their own fork or organization install where they control permissions and scope. ## Fork behavior * **Maintainer-initiated workflows** from the main repo context are supported. * **Machine-initiated automations** are conservative when maintainer linkage is missing or unsafe. This conservative model is intentional to reduce abuse and cross-context data risk in open-source environments. # Daemon-powered PR reviews Source: https://docs.charlielabs.ai/pr-reviews Define your PR review system. Charlie runs it. Every repository has its own definition of useful review. Charlie's `pr-review` [daemon](/daemons) lets your team define that system in your repository and change it as your codebase evolves. **You control judgment; Charlie handles the moving system.** Your policy defines when Charlie reviews, which perspectives matter for a change, what evidence feedback requires, how follow-up reviews behave, and what Charlie may publish. Charlie applies that policy to the current pull request and combines the relevant perspectives into one coherent review. A single broad review pass has to carry every concern at once. Focused review lanes give each perspective a clear job, its own applicability guidance, and an evidence bar. Charlie selects the lanes that are useful for the change instead of running every installed perspective on every pull request. ## How daemon-powered reviews work When a review starts, Charlie loads the policy from your repository's default branch and gathers the current pull request context. That context includes the diff, changed files, checks, discussion, prior feedback, and relevant repository guidance. Charlie inventories the installed review lanes and selects the ones that apply to the change. The selected lanes investigate their focused perspectives independently and in parallel against the same current pull request. Charlie then applies the review-wide policy in `DAEMON.md` to their candidate findings, reconciles overlapping or previously reported feedback, and produces one coherent review or the configured clean result. The policy lives in ordinary Markdown: ```text theme={null} .agents/daemons/pr-review/ ├── DAEMON.md └── references/lanes/ ├── correctness.md └── repository-guidance.md ``` `DAEMON.md` defines when reviews run and the rules shared by the whole review. Each direct Markdown file under `references/lanes/` defines one focused perspective, including when it applies and what evidence a finding needs. Your team changes these files through normal pull requests. After a change reaches the default branch, Charlie loads the updated policy within a few minutes. ## What your team controls and what Charlie handles | Your team controls | Charlie handles | | ------------------------------------------------------------------- | ------------------------------------------------------------------ | | When reviews run | Loading the current pull request and repository context | | Which lanes exist, when they apply, and how deeply they investigate | Selecting applicable lanes and running focused work | | Evidence requirements, exclusions, and finding eligibility | Verifying candidates and applying the root policy | | Presentation, review outcomes, and follow-up review policy | Reconciling overlap and prior feedback, then delivering one review | ## Start from the reference policy The [`pr-review` reference daemon](https://github.com/charlie-labs/daemons/tree/master/daemons/pr-review) gives your team a working starting policy. It begins with two lanes: * **Correctness** looks for reachable behavior errors, broken state or lifecycle invariants, and unhandled failure paths. * **Repository guidance** checks the change against applicable repository instructions and documented contracts. The reference policy reviews when: * A non-draft pull request is opened. * A draft pull request is marked ready for review. * `CharlieHelps` is requested as a reviewer. * A pull request comment requests a review from `CharlieHelps`. It does not review every new commit by default. Your team can request another review explicitly or configure a different cadence. The reference policy publishes findings with a `COMMENT` review. When a completed review is clean, Charlie adds one `+1` reaction to the pull request body instead of posting an empty review or summary. Your team can change the cadence, lanes, evidence rules, presentation, and allowed review outcomes as its needs evolve. ## Get started Most teams should install the reference policy, observe a few representative reviews, and then change one decision at a time. Install the reference daemon and merge its policy into your default branch. Change cadence, review perspectives, evidence rules, and review output. Tune review frequency and scope after observing representative reviews. Diagnose missing, unexpected, or noisy reviews. **Migrating from agent-powered reviews?** Read [Migrate to daemon-powered reviews](/pr-reviews/migrate) to understand what changes and how review coverage works during the transition. # Configure Source: https://docs.charlielabs.ai/pr-reviews/configure Change when Charlie reviews, what he looks for, and how he publishes feedback. The `pr-review` daemon is your repository's review policy. Change it through normal pull requests, and keep each edit focused on one behavior you want to observe. You can ask Charlie in Slack, GitHub, or Linear to update the policy for you: ```text theme={null} Update the `pr-review` daemon so [describe the behavior you want]. Change only the smallest relevant policy section and open a pull request. ``` ## Start from the installed files The reference daemon installs three files: ```text theme={null} .agents/daemons/pr-review/ ├── DAEMON.md └── references/ └── lanes/ ├── correctness.md └── repository-guidance.md ``` * `DAEMON.md` defines when reviews run and the policy shared by every review. * `correctness.md` looks for evidence-backed correctness problems. * `repository-guidance.md` checks applicable repository instructions and durable local conventions. Only direct Markdown files matching `references/lanes/*.md` are review lanes. Files in nested directories are not selected as lanes. Other Markdown under `references/` can provide supporting guidance without becoming a separate review perspective. Start from the [`pr-review` example in `charlie-labs/daemons`](https://github.com/charlie-labs/daemons/tree/master/daemons/pr-review). ## Choose where to make the change Edit the smallest surface that owns the behavior: | What you want to change | Where to change it | | ------------------------------------------------------ | ------------------------------------------------- | | When reviews run | `watch` in `DAEMON.md` frontmatter | | A rule that applies to every review | The relevant policy section in `DAEMON.md` | | One perspective's applicability, concerns, or evidence | Its file in `references/lanes/` | | A new review perspective | A new direct Markdown file in `references/lanes/` | | A development rule for authors and reviewers | Repository instructions or documentation | | Required human approval or merge enforcement | GitHub branch protection or checks | Charlie owns collecting context, running the applicable lanes, and delivering the review. If one of those is not working, use [Troubleshooting](/pr-reviews/troubleshooting) instead of adding execution instructions to your policy. ## Change when reviews run The reference `watch` policy starts a review when: * A non-draft pull request is opened. * A draft pull request is marked ready for review. * `CharlieHelps` is requested as a reviewer. * A pull request comment requests a review from `CharlieHelps`. The reference policy does not review every new commit by default. Review lanes also do not start reviews: `watch` controls cadence, while each lane's applicability guidance controls whether that perspective participates after a review starts. ### Require an explicit request To disable automatic reviews: 1. Remove the conditions for opening a non-draft pull request and marking a draft ready. 2. Keep the conditions for requesting `CharlieHelps` as a reviewer and requesting a review in a pull request comment. Opening or readying a pull request will no longer start a review. Someone must request one explicitly. ### Review every new commit Add this condition to `watch`: ```yaml theme={null} - A new commit is pushed to an open non-draft pull request. ``` Keep the open and ready conditions if you also want an initial automatic review. Reviewing every commit increases review volume and cost, so use focused lanes and a clear rereview policy. ### Leave the daemon's role intact `watch` is the normal cadence control. The reference `purpose` and `routines` define the daemon's role; changing them changes or forks that role. Do not add lane orchestration, package commands, retry behavior, idempotency rules, or publication instructions. Charlie owns those mechanics. Keep this standalone line in the body of `DAEMON.md` exactly once: ```text theme={null} PR review protocol: pr-review/v1 ``` The protocol connects your policy to compatible review mechanics. It is not a package version for your repository to install or pin. ## Configure review-wide policy Use `DAEMON.md` for decisions that must govern the whole review. The reference policy organizes those decisions into nine sections: | Section | What it controls | | ---------------------------- | ---------------------------------------------------------- | | `Never leave feedback about` | Categories excluded from every review lane | | `Review outcomes` | Allowed GitHub review outcomes and clean-review behavior | | `Review depth` | How much context Charlie should inspect | | `Artifact treatment` | How different file and artifact types should be reviewed | | `Findings and verification` | The evidence bar, verification rules, and finding format | | `Incomplete reviews` | What happens when part of a review cannot be completed | | `Review requests` | How focused requests affect the current review | | `Final review` | Finding selection, ordering, placement, and tone | | `Rereviews` | How follow-up reviews treat prior feedback and new changes | The headings are Markdown policy, not a fixed schema. Keep them when they make the policy easy to inspect, and change the content only when you want the corresponding behavior to change. ### Exclusions and evidence Use `Never leave feedback about` for a small number of genuine cross-lane vetoes. The reference policy excludes personal preferences without a concrete risk, pre-existing problems the pull request did not worsen, expected generated-artifact changes without material risk, and problems already explained by deterministic checks or another review. Keep global exclusions narrow. A broad rule can hide a valid finding from every perspective. Put a concern-specific false-positive boundary in the relevant lane instead. `Findings and verification` defines what a candidate must establish before Charlie publishes it. The reference policy requires: * A concrete issue. * A plausible trigger or supporting evidence. * A material consequence. * A clear required action. Charlie can run targeted checks when they resolve a material uncertainty. A failed, unavailable, or inconclusive tool is not evidence by itself. The reference finding header includes severity and the originating lane: ```md theme={null} **1. Short descriptive title** | `🔴 blocking` | `§ correctness` ``` Use `🟠 non-blocking` for findings that do not need to be addressed before merge. Keep the exact lane name so readers can trace the finding to its policy. The reference policy does not use numeric severity or confidence scores. ### Review depth and artifact treatment `Review depth` controls how much surrounding context Charlie should inspect. The reference policy reviews the diff plus enough callers, dependencies, tests, contracts, and repository guidance to establish the effect of the change. Large pull requests do not lower the evidence bar or impose a finding cap. If size or another constraint materially narrows coverage, use the incomplete-review policy instead of lowering the standard. `Artifact treatment` lets you set different expectations for different kinds of files. The reference policy: * Fully reviews runtime code, configuration, schemas, migrations, infrastructure, CI, and dependency manifests. * Reviews tests and fixtures for concrete verification gaps or contract conflicts, not speculative production findings. * Reviews documentation, examples, renames, moves, deletions, and binaries when an applicable rule or concrete material risk exists. * Ignores expected generated, vendored, snapshot, lock, and build-artifact changes unless the artifact itself creates a concrete material risk. Adjust these rules when your repository has a different source-of-truth model or risk profile. ### Review outcomes and incomplete reviews The reference policy permits `COMMENT` only. When useful findings qualify, Charlie publishes them in one `COMMENT` review. When every applicable lane completes with no useful finding and no coverage limitation, Charlie leaves exactly one `+1` reaction on the pull request body. He does not publish an empty review, summary, praise, or `LGTM`. To keep that behavior explicit: ```md theme={null} ## Review outcomes - When publishing a formal PR review, use `COMMENT`. - When a finding should be addressed before merge, say so directly in the finding. - For a clean review, ensure Charlie has exactly one `+1` reaction on the pull request body. - Do not publish a formal review, comment, summary, praise, or `LGTM` for a clean review. ``` You can also authorize `APPROVE` or `REQUEST_CHANGES`. Define an observable threshold for each outcome and decide whether a clean review should produce an approval or retain the reference `+1` behavior. `APPROVE` and `REQUEST_CHANGES` participate in GitHub's review system. GitHub permissions and branch-protection rules determine their merge effect. Repository policy does not replace deterministic merge controls or a required human approval. `Incomplete reviews` controls what happens when Charlie cannot finish every applicable part of a review. The reference policy still publishes independently supported findings and adds at most one concise limitation note. It publishes a limitation-only comment only when silence could reasonably look like a completed clean review. ### Final review presentation Use `Final review` to control: * Which eligible findings appear and in what order. * Inline placement for precise changed-line concerns versus review-body placement for cross-file concerns. * Tone and verbosity. * When a suggested fix is useful. * How overlapping findings should be consolidated. The reference policy publishes every distinct finding that meets the evidence bar. It combines symptoms of one underlying problem, keeps independent risks separate, puts blocking findings first, and omits generic summaries and praise. Avoid a hard finding cap unless your team deliberately accepts the risk of hiding otherwise useful feedback. Narrow lanes and strengthen applicability when you need less noise. ### Focused review requests `Review requests` defines how Charlie treats a comment that asks him to focus on something specific. The reference policy lets the request focus attention for that review, but it cannot suppress applicable lanes or override trusted repository policy. ### Rereviews `Rereviews` defines how follow-up reviews treat the current pull request and earlier feedback. The reference policy: * Considers the full current pull request while focusing on changes since the previous review and behavior those changes affect. * Does not repeat findings that were resolved, dismissed with supporting evidence, or explicitly accepted by an authorized maintainer unless new evidence materially changes the risk. * Avoids duplicating human or automated feedback unless Charlie adds a distinct consequence, requirement, or useful diagnosis. * Corrects or retracts prior Charlie feedback when later evidence shows it was wrong. Charlie-owned mechanics prevent duplicate GitHub mutations. Your policy decides whether the underlying feedback is still useful and should appear again. ## Configure review lanes Each direct Markdown file in `references/lanes/` defines one independently understandable review perspective. Charlie inventories those lanes, selects the applicable ones using their authored applicability guidance, and applies the root policy to the resulting candidates. The installed correctness and repository-guidance lanes are starting choices. You can edit, add, remove, or replace them. ### Write one perspective per lane A lane should answer: 1. When does this perspective apply? 2. Which concrete concerns should it investigate? 3. When is each concern reportable? 4. What evidence must support a finding? Use headings to make those decisions easy to review without treating them as required schema: ```md theme={null} # [Perspective name] ## Applies when - Use this lane when [the change makes this perspective useful]. - Skip it when [the perspective cannot add useful review judgment]. ## Concerns - **[Concrete concern]** - **Report when:** [Observable condition that makes this a real problem.] - **Evidence:** [Code, test, contract, or repository evidence needed to support it.] ``` Add `Do not report` only when a realistic false-positive boundary remains after the report condition and evidence requirement: ```md theme={null} - **Incorrect behavior on a reachable path** - **Report when:** Changed code produces an incorrect result for a concrete input, state, configuration, or dependency result. - **Evidence:** Show how the path is reached, what should happen, what happens instead, and the consequence. - **Do not report:** Hypothetical edge cases without a plausible execution path or observable consequence. ``` A focused lane often contains three to seven coherent concerns. This is an authoring heuristic, not a validation rule. Split a lane when its concerns need materially different applicability or evidence. Combine lanes when they repeatedly investigate the same behavior. ### Prefer conditions and evidence | Avoid | Prefer | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `Review failure handling.` | Report a failure-handling issue only when a reachable path can return the wrong result, conceal a required failure, or leave work incomplete. | | `Report anything that might break.` | Require a concrete reachable path, expected behavior, actual behavior, and material consequence. | | `Never report edge cases.` | Do not report hypothetical edge cases without a plausible execution path or observable consequence. | Use narrow suppressions for recurring false positives. A universal veto usually hides legitimate findings along with the noise. ### Decide which repository sources are authoritative The reference repository-guidance lane uses these defaults: * Policy from the default branch governs the review. * A more specific path instruction can strengthen a root rule, but does not silently weaken it. * Code, tests, schemas, and neighboring files are evidence. They are not automatically policy. * The pull request description and conversation provide context. They are not durable repository policy. Change these rules if your repository has a different documented authority model. Keep the precedence explicit so Charlie does not have to infer it from conflicting examples. ### Narrow, add, or remove a lane When a lane is noisy, make the smallest effective edit: * Narrow its applicability when the whole perspective runs unnecessarily. * Tighten `Report when` when a concern fires without the condition that makes it harmful. * Strengthen `Evidence` when findings are plausible but unsupported. * Add a narrow `Do not report` example for one recurring safe case. * Remove a concern or lane when it no longer earns its review cost. Add a perspective by creating one direct Markdown file in `references/lanes/`. Remove it by deleting that file through a normal pull request. There is no root lane registry to update, and each remaining lane should stay understandable on its own. ## Control cost and scope PR review cost is mainly shaped by cadence, lane count, lane applicability, and review depth. Large pull requests require more investigation, and a review still consumes work when no visible finding qualifies. Start by reducing unnecessary reviews and making applicability more precise. Remove or narrow lanes whose accepted value no longer justifies their cost, latency, or overlap with other perspectives. Change one dimension at a time so you can tell what improved. See [Control PR review costs](/pr-reviews/cost-control) for focused guidance. ## Apply policy changes safely 1. Make one focused edit on a branch. 2. From the repository root, run structural validation: ```bash theme={null} bunx @charlie-labs/daemons validate --all ``` 3. Inspect the diff and explain the intended behavior change in the pull request. 4. Merge the change to the default branch. 5. Allow a few minutes for Charlie to load the updated policy. 6. Exercise the change on a separate representative pull request. 7. Compare the GitHub result and [Dashboard Activity](https://dash.charlielabs.ai/) with the policy. The CLI validates daemon file structure and frontmatter. It does not validate review meaning, lane quality, the PR review protocol, routing, repository access, or live output. PR review policy only takes effect from the default branch. To prevent a change from defining the rules used to judge itself, Charlie does not run a daemon-powered review on a pull request that changes `DAEMON.md` or reference Markdown for the `pr-review` daemon. Merge the policy change, wait for Charlie to load it, and test it on another pull request. Do not broaden the policy merely to make Charlie publish something. A fully completed clean review produces the configured clean result rather than a finding. ## What Charlie handles Your policy defines review judgment. Charlie gathers the current pull request context, inventories the lanes, selects the applicable lanes from their authored guidance, applies the root policy to the resulting candidates, and delivers the review. ## Next steps * [Control PR review costs](/pr-reviews/cost-control) to reduce review frequency or scope. * [Troubleshooting](/pr-reviews/troubleshooting) when a review does not run or its result is unexpected. * [PR review overview](/pr-reviews) for the product model and setup path. * [`DAEMON.md` reference](/daemons/daemon-md-reference) for the generic daemon file contract. # Cost controls Source: https://docs.charlielabs.ai/pr-reviews/cost-control Control PR review credit usage by changing when reviews run and which review lanes apply. PR review credit usage depends on how often Charlie reviews and how much work each review requires. Your repository's `pr-review` policy controls both. There is no fixed credit cost or universal maximum for a review. One review may use a single credit while another uses much more because pull request size, complexity, and selected review lanes vary. Use actual reviews in Dashboard Activity to decide whether the value and cost are right for your team. ## Start with the reference policy The reference daemon is a conservative starting point. It reviews a pull request when it first becomes ready for review, then waits for an explicit request before reviewing it again. It begins with two lanes: correctness and repository guidance. Keep those defaults for a few representative reviews before changing them. You will get a better result by tuning observed usage than by trying to predict one universal credit amount. ## Check credit usage in Activity Open [Dashboard > Activity](https://dash.charlielabs.ai/) and: 1. Choose a time range with representative pull requests. 2. Filter to GitHub, **Daemon**, and `pr-review`, or search for the repository. 3. Compare the number of review entries and the **Credits** value for each one. 4. Follow the source links to see which pull requests were small, large, simple, or complex. Look at both parts of the pattern: * Many review entries usually point to review frequency. * A smaller number of expensive reviews usually points to pull request complexity or the lanes selected for those changes. A review can use credits even when Charlie publishes no finding. He still has to load the pull request, decide which lanes apply, and investigate the change before reaching a clean result. ## Choose how often reviews run Review frequency is the most direct cost control. Configure it with `watch` in `.agents/daemons/pr-review/DAEMON.md`. | Automatic frequency | What happens | Relative usage | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------- | | Initial review only | Charlie reviews when a non-draft pull request opens or a draft becomes ready. Your team can still request another review explicitly. | Lowest | | Initial review plus substantial updates | Charlie also reviews pushes that meet your team's definition of a substantial change. | Moderate | | Initial review plus every commit | Charlie reviews every new commit pushed to an open, non-draft pull request. | Highest | Explicit reviewer requests and `@CharlieHelps` comments add to review frequency, so team habits around them affect usage alongside the automatic policy. ### Review only substantial updates Add a push condition to `watch` with a concrete, observable threshold for when an update merits another review. Your threshold might use change size, a material behavior change, or changes under high-risk paths. Choose a condition your team can predict, and avoid vague wording that could match every push. ### Review every commit Add this condition when the additional coverage is worth the additional usage: ```yaml theme={null} - A new commit is pushed to an open non-draft pull request. ``` This is useful for teams that want Charlie to follow every iteration. It can create several full reviews for one pull request, especially when authors push small fixes frequently. See [Configure > Change when reviews run](/pr-reviews/configure#change-when-reviews-run) for the full cadence guidance. ## Reduce the work in each review The work required for one review depends mainly on the pull request and the lanes Charlie selects. ### Keep lane applicability narrow Every installed lane must be considered. Each lane selected for the current pull request adds focused investigation and contributes candidates to the final review. Write clear applicability guidance so specialized lanes run only where they can add useful judgment. For example, a migration-safety lane should skip pull requests that do not change schemas, migrations, stored data, or compatibility behavior. ### Remove low-value or overlapping lanes More lanes are useful only when they contribute distinct review value. If two lanes repeatedly inspect the same concerns, clarify their boundaries or combine them. Remove a lane when its accepted findings no longer justify its credit use or overlap with other perspectives. Do not use a finding cap as the first cost control. Charlie performs the review work before deciding which findings qualify, so a cap can hide useful feedback without meaningfully reducing the work already done. ### Keep pull requests reviewable Large or cross-cutting pull requests require more context and investigation. Split changes when that also improves your team's normal development and review workflow. Do not weaken the evidence bar for large pull requests. If a specialized lane is expensive on broad changes, narrow when that lane applies instead of asking Charlie to review less carefully. See [Configure > Configure review lanes](/pr-reviews/configure#configure-review-lanes) to edit applicability, add or remove lanes, and reduce overlap. ## Decide what to change | What you see in Activity | Start here | | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | More reviews per pull request than expected | Narrow `watch` or reduce unnecessary explicit requests. | | A reasonable number of reviews, but high credits per review | Check pull request size and which lanes are likely to apply. | | One specialized perspective rarely produces useful feedback | Narrow its applicability or remove the lane. | | Several lanes produce overlapping feedback | Clarify their boundaries or combine them. | | Usage spikes on large, cross-cutting pull requests | Split changes when practical or narrow expensive specialized lanes. | | Clean reviews still use more credits than they are worth | Reduce review frequency or lane scope; clean output does not mean no review work occurred. | Change one control at a time. Merge the policy update to the default branch, allow a few minutes for Charlie to load it, then compare the next set of representative reviews in Activity. You can ask Charlie in Slack, GitHub, or Linear to make the focused policy change and open a pull request: ```text theme={null} Update the `pr-review` daemon to [describe the frequency or lane change]. Change only the smallest relevant policy section and open a pull request. ``` ## Next steps * [Configure](/pr-reviews/configure) for complete cadence and lane-authoring guidance. * [Troubleshooting](/pr-reviews/troubleshooting) if Activity or GitHub output does not match the policy. * [PR review overview](/pr-reviews) for the full setup and migration path. # Migrate to daemon-powered reviews Source: https://docs.charlielabs.ai/pr-reviews/migrate Move from Charlie’s agent-powered PR reviews to our new daemon-powered PR reviews. Charlie's existing PR reviews use policy managed by us. [Daemon](/daemons)-powered reviews move that policy into your repository, where your team can inspect and change it through normal pull requests. You decide when Charlie reviews, which perspectives apply, what evidence feedback requires, and what Charlie may publish. Charlie handles running that policy against the current pull request and delivering the review on GitHub. ## What changes The GitHub experience remains familiar. Charlie still reviews pull requests, and your team can still request a review by adding [`CharlieHelps`](/integrations/github-identities) as a reviewer or mentioning him in a pull request comment. The main change is who controls the review policy: | Agent-powered reviews | Daemon-powered reviews | | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | Review policy is managed by us. | Review policy lives in your repository. | | Your team cannot directly inspect or edit when and how reviews run. | Your team changes cadence and review guidance through normal pull requests. | | Automatic and explicit reviews are handled by the Charlie agent. | Automatic and explicit reviews follow the same repository-owned daemon policy. | | Review perspectives and output are controlled outside your repository. | `DAEMON.md` and focused lane files define what Charlie reviews and what he may publish. | Policy changes take effect after they reach the repository's default branch. Charlie loads the updated policy within a few minutes. ## Start with the reference policy We recommend starting with the reference `pr-review` daemon so you have a known baseline for migration. It is based on Charlie's existing review behavior, with focused correctness and repository guidance perspectives, an evidence bar for findings, and rules that avoid low-value feedback such as personal style preferences or problems the pull request did not introduce. The reference daemon does not review every new commit by default. This is the main cadence change from agent-powered reviews. It reviews when: * A non-draft pull request is opened. * A draft pull request is marked ready for review. * `CharlieHelps` is requested as a reviewer. * A pull request comment requests a review from `CharlieHelps`. You can request another review explicitly or change the cadence later. The reference policy publishes findings with a `COMMENT` review. When a completed review is clean, Charlie adds one `+1` reaction to the pull request body instead of posting an empty review or summary. ## How reviews are routed during the transition You do not lose review coverage while the new experience rolls out. | Repository state | During the transition | After the transition | | ---------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | `pr-review` is installed | Automatic and explicit reviews use the repository-owned daemon policy. | Automatic and explicit reviews use the repository-owned daemon policy. | | `pr-review` is not installed | Automatic and explicit reviews fall back to the Charlie agent. | Automatic reviews do not run. Explicit requests continue to use the Charlie agent. | Agent-powered automatic reviews are a temporary fallback. Install the `pr-review` daemon to keep automatic reviews enabled after the transition. ## Migrate your repository to daemon-powered reviews 1. Follow [Set up PR reviews](/pr-reviews/setup) to install the reference daemon. Installing from the Charlie dashboard or asking Charlie creates a pull request for your team to review. 2. Review the starting policy. Before merging the installation pull request, you can optionally: * Add `A new commit is pushed to an open non-draft pull request.` to `watch` in `DAEMON.md` if you want Charlie to review every new commit pushed to the pull request. * Update **Review outcomes** in `DAEMON.md` to allow Charlie to submit `APPROVE` or `REQUEST_CHANGES` reviews in addition to `COMMENT`. Define when each outcome should be used. 3. Merge the installation pull request into the repository's default branch. 4. Allow a few minutes for Charlie to load the policy. Observe a few representative reviews in GitHub and [Dashboard Activity](https://dash.charlielabs.ai/). 5. Keep the reference policy if it works for your team. When you find a specific behavior to change, use [Configure PR reviews](/pr-reviews/configure) and adjust one decision at a time. Reviewing every push increases usage. [Cost controls](/pr-reviews/cost-control#review-only-substantial-updates) describes a middle ground that reviews only substantial updates. If you are not ready to migrate, agent-powered reviews will continue during the transition. Install `pr-review` before the transition ends to keep automatic reviews running. ## Next steps Install the reference daemon and merge its policy into your default branch. Change cadence, review perspectives, evidence rules, and review output. Tune review frequency and scope after observing representative reviews. # Setup Source: https://docs.charlielabs.ai/pr-reviews/setup Install the `pr-review` daemon and confirm your first PR review. Install the `pr-review` daemon to define Charlie's pull request review policy in your repository. Installation creates a normal pull request, so your team can inspect the policy before Charlie uses it. You are done when the daemon files are on the repository's default branch and Charlie has loaded the policy, which usually happens within a few minutes. The daemon can then activate when a pull request event or explicit request matches its `watch` policy. ## Before you start Complete the [Charlie GitHub integration](/integrations/github) for this repository so Charlie can access it. Inviting `@CharlieHelps` is optional. It lets teammates request reviews through GitHub's reviewer picker or pull request comments. Learn more about [Charlie's GitHub identities](/integrations/github-identities). Make sure someone on your team can merge the installation pull request. ## 1. Install the daemon Installing from the dashboard is the fastest option. You can also ask Charlie on Slack, GitHub, or Linear, or use the daemons CLI for a local workflow. Each method installs the same reference policy. 1. Open the [Charlie dashboard](https://dash.charlielabs.ai/). 2. Navigate to the **Overview** page. 3. Click **Add daemon** for the desired repository. 4. Click **Add daemon to repo** for the `pr-review` daemon. 5. Open the installation pull request. The dashboard does not write directly to the default branch. Charlie starts using the policy only after your team merges the pull request. Ask Charlie on Slack, GitHub, or Linear. Name the repository if it is not clear from context. For example: ```text theme={null} Add the `pr-review` daemon from `charlie-labs/daemons` to this repository using the daemons CLI ``` Charlie will open an installation pull request for your team to review. Use the daemons CLI if you prefer to install the files locally. Run this command from the repository root: ```bash theme={null} bunx @charlie-labs/daemons add pr-review ``` Inspect the files, commit them on a branch, and open a normal pull request. ## 2. Review the installation pull request The [reference `pr-review` daemon](https://github.com/charlie-labs/daemons/tree/master/daemons/pr-review) adds three files: ```text theme={null} .agents/daemons/pr-review/ ├── DAEMON.md └── references/ └── lanes/ ├── correctness.md └── repository-guidance.md ``` * `DAEMON.md` defines when reviews run and the policy shared by the whole review. * `correctness.md` looks for evidence-backed correctness problems. * `repository-guidance.md` checks applicable repository instructions and durable local conventions. The reference policy starts with these defaults: | Choice | Reference default | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | When reviews run | When a non-draft pull request opens, a draft becomes ready, `CharlieHelps` is requested as a reviewer, or a comment requests a review from `CharlieHelps`. It does not run after every push. | | Review perspectives | Correctness and repository guidance. | | Review outcomes | `COMMENT` only. Findings must meet the evidence and usefulness bar, and there is no fixed finding cap. | | Clean review | Charlie adds one `+1` reaction to the pull request body instead of posting an empty review or comment. | | Final review | Precise findings appear inline when possible. Cross-file concerns appear in the review body. Generic summaries and praise are omitted. | If you are unsure, keep the reference defaults. You can change them after seeing the first review. ### Optional changes before your first review Most teams should merge the reference policy unchanged. Consider these two changes now only if they match how your team already reviews pull requests. 1. **Review every push.** Add this condition to the `watch` section in `DAEMON.md`: ```text theme={null} A new commit is pushed to an open non-draft pull request. ``` This increases review frequency and cost. Without it, follow-up reviews require an explicit request. For a middle ground, review only substantial updates; see [Cost controls](/pr-reviews/cost-control#review-only-substantial-updates). 2. **Allow decision reviews.** Update the review outcomes in `DAEMON.md` to permit `APPROVE` or `REQUEST_CHANGES` in addition to `COMMENT`. Define a clear threshold for each outcome so Charlie knows when it is appropriate. For the first review, leave the lanes, suppressions, evidence rules, presentation, and rereview policy unchanged. Starting from a known baseline makes later changes easier to evaluate. ## 3. Merge the installation pull request Merge the installation pull request into the repository's default branch. Charlie loads the policy from the default branch, so changes in an open pull request are not used yet. Charlie loads the policy within a few minutes after the daemon files reach the default branch. A matching pull request event or explicit request can then activate the daemon. Installation does not automatically review pull requests that are already open. Explicitly request a review for an existing pull request, or wait for a new configured event. ## 4. Confirm your first review Choose a small, representative pull request and request `CharlieHelps` as a reviewer or ask `CharlieHelps` for a review in a pull request comment. The explicit request uses the same repository-owned policy as automatic reviews. When a finding qualifies, the reference policy publishes a `COMMENT` review. When the review is clean, Charlie adds one `+1` reaction to the pull request body. You can also open [Dashboard > Activity](https://dash.charlielabs.ai/) to confirm that Charlie handled the request. If the expected review activity or GitHub output does not appear, see [Troubleshoot PR reviews](/pr-reviews/troubleshooting). ## Next steps * [Configure PR reviews](/pr-reviews/configure) to change cadence, review lanes, outcomes, presentation, or follow-up behavior. * [Control PR review costs](/pr-reviews/cost-control) to tune review frequency and scope. * [Troubleshoot PR reviews](/pr-reviews/troubleshooting) if a review does not run or the result is unexpected. # Troubleshooting Source: https://docs.charlielabs.ai/pr-reviews/troubleshooting Diagnose missing, unexpected, or noisy PR reviews. When a PR review is missing or unexpected, start with the repository state, the event that should have started the review, Dashboard Activity, and the resulting GitHub output. Check those before changing review policy. ## Start with Dashboard Activity Open [Dashboard > Activity](https://dash.charlielabs.ai/) and find the request: 1. Choose a time range that includes the pull request event or explicit request. 2. Filter to GitHub, **Daemon**, and `pr-review`, or search for the repository. 3. Follow the source link back to the pull request and compare the timing with GitHub. Activity can confirm that Charlie handled the request and identify whether it ran as a daemon or an agent task. It does not explain which lanes applied or why a particular finding did or did not qualify. If the request appears as **Agent** even though `pr-review` is installed, confirm that the daemon files reached the default branch and that the comment explicitly asked Charlie for a review. If the files and request are correct, [contact support](#get-help). ## Charlie did not review the pull request Check these in order. ### Confirm that the daemon is on the default branch Charlie loads `DAEMON.md` and its lane files from the repository's default branch. Files that exist only in an installation or configuration pull request are not used. After the files reach the default branch, allow a few minutes for Charlie to load the policy. Installation does not start reviews for pull requests that were already open. ### Confirm that a matching event happened after Charlie loaded the policy The reference policy starts a review when: * A non-draft pull request is opened. * A draft pull request is marked ready for review. * `CharlieHelps` is requested as a reviewer. * A pull request comment requests a review from `CharlieHelps`. The reference policy does not review every new commit. For an already-open pull request or a follow-up review, request `CharlieHelps` as a reviewer or leave a clear comment such as: ```text theme={null} @CharlieHelps, review this PR. ``` If your repository uses different `watch` conditions, compare the event with the current policy on the default branch. ### Check the pull request and repository Confirm that the pull request is open and ready for review and that the [Charlie GitHub integration](https://docs.charlielabs.ai/integrations/github) still has access to the repository, including that `@charliehelps` has been invited as a collaborator on the relevant repository or organization. ## Policy changes are not taking effect PR review policy only takes effect from the default branch. To prevent a change from defining the rules used to judge itself, Charlie does not run a daemon-powered review on a pull request that changes `DAEMON.md` or reference Markdown for the `pr-review` daemon. Merge the policy change, allow a few minutes for Charlie to load it from the default branch, and then exercise it on a separate pull request with a new matching event or explicit request. ## Activity exists, but GitHub output is unexpected The reference policy has two normal visible results: * When useful findings qualify, Charlie submits one `COMMENT` review. * When every applicable lane completes with no useful finding and no coverage limitation, Charlie leaves exactly one `+1` reaction on the pull request body. A clean review does not produce an empty formal review, top-level comment, summary, praise, or `LGTM`. Check the pull request body reactions as well as the review timeline. If [Dashboard > Activity](https://dash.charlielabs.ai/) shows that the task needs attention, follow its source link and confirm that the pull request is still open, ready for review, and accessible. If Activity and the current GitHub state do not explain the missing result, contact support rather than weakening the evidence bar or adding execution instructions to `DAEMON.md`. ## The review ran, but its behavior was wrong Edit the smallest customer-owned policy surface that controls the behavior. | Observed behavior | Change | | -------------------------------------------------- | ----------------------------------------------------------------- | | Reviews run at the wrong time | `watch` in `DAEMON.md` | | A category should never be reported | Review-wide prohibitions in `DAEMON.md` | | A review perspective is missing | Add or revise a direct lane file matching `references/lanes/*.md` | | A lane runs on irrelevant pull requests | Its applicability guidance | | One concern produces recurring false positives | Its `Report when`, `Evidence`, or a narrow suppression | | Charlie uses the wrong formal review event | Review outcomes in `DAEMON.md` | | Feedback is too long, poorly ordered, or misplaced | Final-review policy in `DAEMON.md` | | Reviews cost too much for their value | [Control PR review costs](/pr-reviews/cost-control) | See [Configure PR reviews](/pr-reviews/configure) for examples. Charlie owns running the review and delivering its GitHub output. Do not try to repair those behaviors by adding orchestration or publication instructions to repository policy. ## Get help If these checks do not explain the behavior, email [support@charlielabs.ai](mailto:support@charlielabs.ai) with: * The GitHub pull request URL and repository. * The approximate time of the event or explicit request. * What you expected to happen. * What happened instead. * The smallest relevant `watch` or policy excerpt, when configuration may be involved. Do not include credentials or private provider configuration. # Repo Safety Source: https://docs.charlielabs.ai/repo-safety How to make your repo safe for agents. Configure your repo so agents and automations can’t merge code without human approval. This is a best practice that teams should follow regardless of whether they use Charlie or not. This is a customer-configured GitHub control, not a Charlie product guarantee. Your organization owns the configuration and GitHub enforces them. Charlie cannot bypass GitHub rulesets. ## Before you start * Ensure you have a GitHub team that includes every trusted human who should approve PRs. You can use an existing team, such as `engineering`, or create one. * Ensure your repo is organization-owned. GitHub's team reviewer requirements are not available for user-owned repos. * Ensure your GitHub plan and repo type [support rulesets and required reviewers](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets). ## Configure the merge gate Create a branch ruleset for `main` and any release branches that need the same protection. Configure it to: 1. Require changes to arrive through a pull request. 2. Require one approval from the team with the humans who can approve PRs. The rule is simple: agents can propose and review code; a human must explicitly approve before it merges. See GitHub's [ruleset rule reference](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets) for the current controls and reviewer requirements. ## FAQ ### Should we use CODEOWNERS instead? Use `CODEOWNERS` when the required human reviewer depends on the files changed—for example, require Security for authentication code and Platform for infrastructure. Add the relevant team to `CODEOWNERS`, then enable **Require review from Code Owners** in the ruleset. A code-owner team must be visible and have write access; if multiple owners match, approval from any one of them is sufficient. [GitHub Docs](https://docs.github.com/en/enterprise-cloud@latest/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) ### How do we do this with classic branch protection? Classic branch protection does not offer direct required-team approval quotas. Put the human team in `CODEOWNERS`—using a catch-all pattern if it should review every PR—and enable **Require review from Code Owners**. [GitHub Docs](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches) ### Should we dismiss stale approvals? For stronger protection, enable **Dismiss stale pull request approvals when new commits are pushed**. This invalidates approvals when the reviewed diff changes, requiring a human to approve the updated code. [GitHub Docs](https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets) ### What is the trust boundary? Keep the team used for required reviews human-only, do not give agents bypass or admin permissions, and protect human credentials. GitHub cannot distinguish an agent using a human’s account or token from that human. ### Do auto-merge and merge queue bypass the gate? No. [Auto-merge](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-auto-merge-for-pull-requests-in-your-repository) waits for merge requirements to pass. A [merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) also applies the branch's merge requirements. Verify both in your repository because layered rulesets and branch protection can add more conditions. # Skills Source: https://docs.charlielabs.ai/skills Define reusable task-shaped playbooks and invoke them on demand. Skills are reusable, task-shaped playbooks for work you run repeatedly. ## Required location Store each skill at: `.agents/skills//SKILL.md` Example: `.agents/skills/upgrade-deps/SKILL.md` ## Invocation Call a skill by name in your request: `$` Example: `$upgrade-deps` ## Minimal skill anatomy A strong `SKILL.md` should include: * **Goal**: what outcome the skill produces. * **Inputs**: what context or parameters it expects. * **Steps**: the execution sequence. * **Return shape**: what output format to return. * **Guardrails**: hard boundaries and safety constraints. ## Instructions vs. skills * Put durable repo policy in [AGENTS.md or CLAUDE.md instructions](/AGENTS.md-instructions). * Put repeatable task workflows in skills. If something should apply to every run, put it in the repository-root `AGENTS.md` or `CLAUDE.md`. Use nested instruction files for subtree-specific guidance. If it should apply only when explicitly requested, it belongs in a skill. # Troubleshooting Source: https://docs.charlielabs.ai/troubleshooting Fast triage for setup, trigger, and run issues. Use this page for fast triage when Charlie is not responding or output doesn’t match expectations. ## Fast triage checklist 1. Confirm the repo is in scope for your `CharlieCreates` GitHub App installation. 2. Confirm `CharlieHelps` is available when you expect GitHub mentions, review requests, or assignments to work. 3. Confirm the triggering user has the required permissions on that surface. 4. Confirm Charlie was explicitly invoked (mention/review request/assignment) when needed. 5. Confirm required integrations are connected for the workflow you expect. 6. For Linear workflows, confirm the issue's Linear team is mapped to the intended repo. For Slack workflows, confirm the Slack workspace is mapped to the intended repo. 7. Re-run the request with a concrete, scoped instruction. For daemon-specific rollout/debugging, use [Testing and iterating on daemons](/daemons/testing-and-iterating-on-daemons). ## Common issues → next action ### Run failed mid-task * Read the failure message in the thread. * Re-trigger with explicit continuation context (what failed + what to try next). * If failures repeat, include exact command output in your follow-up. ### Charlie not visible in Linear assignee/search * Invite Charlie to the Linear workspace and any Linear teams where you expect him to appear. * Recheck the relevant Linear team mapping in your integration settings. ### No response on GitHub * Verify `CharlieCreates` is installed on that repo. * For mentions, PR review requests, or assignment-style workflows, verify `CharlieHelps` is available in the repo or organization. * Confirm the event is one Charlie responds to (mention, review request, assignment, eligible PR event). * Confirm the sender has sufficient permissions for that repo context. * See [GitHub App and user](/integrations/github-identities) if you are not sure which identity to check. ### No response on Linear * Confirm the Linear integration is connected. * Confirm the issue's Linear team is mapped to the intended repo. * For a direct request, use `@Charlie` in a supported issue comment, or assign the issue to Charlie when assignment is the intended action. * For a daemon wake, confirm the new issue or issue comment matches the daemon `watch`; issue comments do not need to mention Charlie. * Confirm the sender can access both the Linear issue and the mapped repo context. ### No response on Slack * Confirm the Slack integration is connected. * Confirm the Slack workspace is mapped to the intended repo. * Confirm Charlie can access the channel, thread, or DM where the request was made. * Use `@Charlie` for direct asks in Slack. For daemon watches on broader channel messages, make sure daemon `watch` wording or body policy narrows the wake to intentional channels. ### Daemon didn’t wake from a Linear or Slack event * Confirm the daemon file is merged on the repo default branch and has been ingested by Charlie. * For Linear, confirm the integration is connected and the issue's Linear team maps to the intended repo. For Slack, confirm the integration is connected and the Slack workspace mapping points to the intended repo. * Confirm the event is supported context: Linear issue creation, issue comments on mapped issues, including comments that do not mention Charlie, issue mentions, and issues assigned to Charlie; or Slack mentions/thread replies, channel messages, and DMs. * Confirm the triggering user and Charlie have permission to read the source issue, channel, thread, or DM. * Make the `watch` entry concrete and provider-visible, such as “A Linear issue is created” or “A Linear issue comment is added on an issue.” ### Mention doesn’t trigger * Use `@CharlieHelps` exactly in a supported comment/review context. * If using review comments, ensure it’s in a submitted review context when required. ### Charlie says it committed, but no commit appears * Check branch protection and required status rules. * Check whether local commit hooks or verification steps failed before push. * Ask Charlie to report branch name + exact failed command output. ### CI mismatch (Charlie passed locally, CI failed) * Compare environment variables and runtime versions between devbox and CI. * Ask Charlie to reproduce using the same script target CI runs. ### External CI logs (non-GitHub Actions) * Paste failing log excerpts or attach machine-readable test artifacts in-thread. * Ask Charlie to diagnose from that output and propose/apply a fix. ## Escalation checklist If you contact support, include: * **Where it was triggered** (GitHub/Linear/Slack + link) * **The failing message or error text** * **What you already tried** (steps + outcomes) Send details to [support@charlielabs.ai](mailto:support@charlielabs.ai).