---
title: Troubleshooting
description: Symptoms you may hit running Foreman, each traced to the code path that causes it, from silent label intake to parked writes in the dev TUI.
type: troubleshooting
summary: Common symptoms, what in the code causes each, and how to fix it.
related:
  - /docs/getting-started
  - /docs/intake
  - /docs/configuration
---

# Troubleshooting



Most surprises with the software factory come from a gate doing its job. This page maps each symptom to the code path behind it, so that you and your agent can understand why something might be wrong.

Terms like parks, unattended, and trusted are defined in the [glossary](/docs/glossary).

## Intake

<Accordions type="single">
  <Accordion title="Labeling an issue does nothing">
    Three gates sit in front of unattended label intake, and all three fail quietly by design.

    The most common cause is that the labeler lacks permission. `isTrustedLabeler` asks the GitHub API for the sender's collaborator permission and requires at least `triage`. It fails closed, so a non-ok response or any API error also means no session. This gate exists because GitHub fires the `labeled` action even for labels attached at issue creation, which issue templates let unauthenticated reporters do.

    The second is the webhook subscription. Unattended intake needs the `issues` event on the GitHub connector, so check the connector's subscriptions.

    The third is the label itself. The hook compares against `FACTORY_LABEL`, which defaults to `factory`, and a custom value has to match exactly.

    Bot senders are skipped outright, so a label applied by an automation will not start a run.
  </Accordion>

  <Accordion title="Mentioning the bot does nothing">
    `onComment` dispatches only for commenters whose `author_association` is `OWNER`, `MEMBER`, or `COLLABORATOR`. Everyone else is acknowledged without a session, which is what stops arbitrary accounts on a public repository from driving the write tools.

    The mention also has to match the resolved bot name. That name comes from `FACTORY_BOT_NAME`, then `GITHUB_APP_SLUG`, then the connector's app slug, falling back to `Foreman`. If you renamed the GitHub App, the mention follows the app, not the docs.

    Check that the connector subscribes to `issue_comment` and `pull_request_review_comment`.
  </Accordion>

  <Accordion title="Red CI never triggers a fix run">
    `onCheckSuite` requires all of the following, and drops the event otherwise.

    * The connector subscribes to the `check_suite` webhook event.
    * The suite `action` is `completed` and its `conclusion` is `failure`.
    * The suite is attached to a pull request.
    * The pull request's head branch starts with `FACTORY_BRANCH_PREFIX`, default `factory/`.

    If everything matches and the run still does nothing, it may have hit its cap. The loop counts its own earlier fix-attempt comments on the pull request thread and stops at 2, posting one comment saying further troubleshooting needs a person. Each dispatch is a fresh session, so the thread is the only record those runs share.

    The branch-prefix gate is the whole scope of this surface. Pull requests people pushed are never touched, however red their checks are.
  </Accordion>

  <Accordion title="New branches fall outside the CI fix loop after changing the prefix">
    `FACTORY_BRANCH_PREFIX` changes what the red-CI hook recognizes as a factory branch, but not what the Implementer is told to name its branches. The station's instructions describe the naming in prose, with `factory/` written into the text.

    Set the environment variable and edit `agent/subagents/implementer/instructions.md` to match. The [configuration](/docs/configuration) page carries a prompt that changes both at once.
  </Accordion>
</Accordions>

## Setup and deployment

<Accordions type="single">
  <Accordion title="The build fails during discovery">
    Two variables are read with `requireEnv` at module load, so a missing value fails the build rather than surfacing mid-request.

    `FACTORY_REPO` is required and validated as exactly one `owner/repo` pair. A malformed value throws the same way a missing one does.

    `LINEAR_CONNECTOR` is required by `linearAuth` in `agent/lib/constants.ts`. The Linear channel has its own fallback, but the auth helper does not, so discovery fails without it even if you are not using Linear.

    Run `npx eve info` to see the discovered surface and the diagnostics behind a failure.
  </Accordion>

  <Accordion title="Foreman is operating on the wrong repository">
    It cannot, unless `FACTORY_REPO` itself is wrong. The GitHub extension sets `context: factoryRepo`, which fills `owner` and `repo` on every call from `FACTORY_REPO`. There is no parameter for the model to redirect.

    Check the value in the Vercel project's environment variables. Note that changing it also changes the [factory brain](/docs/memory) key, since the key derives from a hash of `FACTORY_REPO`. Retargeting gives you a fresh brain rather than mixing facts across codebases.
  </Accordion>

  <Accordion title="Local runs fail on auth">
    `vercel env pull` supplies a short-lived OIDC token, and that token is what Connect credentials, Vercel Blob, and the station sandboxes all authenticate with. There are no static keys to set.

    If local runs worked earlier in the day and now fail, the token has likely expired. Run `vercel env pull` again.
  </Accordion>
</Accordions>

## Running the pipeline

<Accordions type="single">
  <Accordion title="Every GitHub write parks in the dev TUI">
    This is intended. The dev principal is deliberately untrusted, so writes stop on an approval card and wait for you.

    It doubles as a live demo of the human gate: you see exactly which actions Foreman would have taken and approve or deny each one. Nothing is misconfigured.
  </Accordion>

  <Accordion title="The review finished but no pull request appeared">
    The line stops without opening a pull request in two cases.

    The Reviewer returned `reject`, meaning the approach itself is wrong and iteration will not fix it. Or the work went through 2 revision cycles and still did not pass.

    In both cases the orchestrator reports the unresolved findings on the originating thread rather than shipping something the Reviewer would not sign off on. Read those findings, then re-file the work with the gap addressed.
  </Accordion>

  <Accordion title="The run stopped and asked questions instead of building">
    The Classifier set `needs_clarification`, which is the pipeline's stop signal. It does that only when proceeding would risk building the wrong thing entirely.

    On an attended run, answer in the thread and the run continues. On an unattended run, the questions are posted as a comment and the run ends, because an unattended run is never left waiting on input. Answer, then re-apply the label to start a fresh run.
  </Accordion>

  <Accordion title="A station missed something the factory already knew">
    Stations inherit nothing from the root, and that includes the [factory brain](/docs/memory). They cannot read it.

    The orchestrator is responsible for weaving relevant repository facts into each station's delegation message. If a station keeps rediscovering the same quirk, the fix is usually to record it in the brain so the orchestrator can pass it along, or to check that the brain entry is specific enough to be worth forwarding.
  </Accordion>

  <Accordion title="An unattended run says it could not do something">
    Unattended runs are denied rather than parked, because nobody is watching to clear an approval card. A denial resolves in one step and the run reports what it could not do.

    The writes an unattended run does have are labels, comments on its own stamped intake issue, closing or reopening issues, and opening a draft pull request. Everything else is refused. The [trust model](/docs/trust-model) explains the reasoning per policy.
  </Accordion>
</Accordions>

## Evals

<Accordions type="single">
  <Accordion title="needs-connect evals fail">
    Those cases assert tool calls that must succeed against real Connect auth, so they need a linked project with working connectors.

    ```bash
    vercel link
    vercel env pull
    pnpm eval --tag needs-connect
    ```
  </Accordion>

  <Accordion title="routing/labels-follow-classification fails">
    That case needs at least one open issue numbered `#1` on `FACTORY_REPO`, because the eval asks the agent to classify that specific issue. Open one on your scratch repository and re-run.
  </Accordion>

  <Accordion title="A new write tool is not being guarded">
    Read-only evals assert `notCalledTool` over the shared `WRITE_TOOLS` list in `evals/helpers.ts`, not over individually named tools. A write tool added to the extension's `include` allowlist is only covered once it is added to `GITHUB_WRITE_TOOLS` there.

    The [evals](/docs/evals) page carries a prompt that adds the tool to the list and writes a matching safety case.
  </Accordion>
</Accordions>

## Next steps

<Cards>
  <Card href="/docs/intake" title="How work arrives" description="The six surfaces, what each one trusts, and what each one triggers." />

  <Card href="/docs/configuration" title="Configuration" description="Every environment variable and what it controls." />

  <Card href="/docs/trust-model" title="Trust model" description="Why unattended runs are denied instead of parked." />
</Cards>


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)