theam / theam/facility

facility init writes unparseable agent workflows when no provision command is detected

Open
#217 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
71
Forks
64
Avg merge
15h 38m
Merged PRs (30d)
66

Description

Summary

On a repository where facility init cannot detect a provision command, the generated
facility-crew.yml and facility-codex.yml are not valid YAML. GitHub cannot parse them, so
the agent triggers never run — /architect and /builder do nothing at all. facility doctor
reports the installation as healthy.

The repository this happened on is a small public Node/pnpm service with Prisma and a
docker-compose file. Nothing exotic.

What happens

init interpolates the provision command into a bare YAML scalar:

# packages/cli/templates/workflows/facility-crew.yml
run: {{PROVISION_CMD}}

With no provision command detected, init.mjs substitutes its own fallback
(src/init.mjs, ~line 381):

const provisionCmd =
  provision ||
  'echo "facility: no provision command configured — the crew runs on a bare checkout. Set one in this workflow + .facility.json."';

That string contains facility: . In a bare scalar the colon-space starts a mapping, and the
file stops parsing:

.github/workflows/facility-crew.yml:196:27: could not parse as YAML:
mapping values are not allowed in this context [syntax-check]

196 | run: echo "facility: no provision command configured — the crew runs on a bare checkout...
                       ^~

Both agent triggers are affected. In GitHub's UI the runs appear named by file path rather than
workflow name, with This run likely failed because of a workflow file issue and no usable log.

This is not limited to the fallback

Any provision command containing ": " breaks identically. This is an ordinary thing to write:

$ facility init --yes --provision='docker compose up -d && echo "db: ready"'
.github/workflows/facility-crew.yml:202:45: could not parse as YAML:
mapping values are not allowed in this context [syntax-check]

Reproduction

mkdir repro && cd repro && git init -b main
printf '{"name":"x","private":true,"scripts":{"test":"vitest run"}}' > package.json
echo '{}' > package-lock.json
node /path/to/facility/packages/cli/bin/facility.mjs init --yes
actionlint .github/workflows/facility-crew.yml

doctor does not catch it

On a complete install whose crew workflow cannot be parsed, facility doctor --run-guards
reports:

  ✓ .facility.json — engines claude-code,codex, models build=opusplan, ...
  ✓ provision — docker compose up -d && echo "db: ready"
  ✓ checks — npm test
  ✓ guards/run.mjs — Guards pass

  Everything checkable checks out.

doctor is the command README points to immediately after init, so nothing between
installation and a silently dead loop reports a problem. The first signal is a failed run
notification after pushing.

Why this matters more than the parse error

The repositories that hit this are exactly the ones with no provision command — the unprepared
ones. A repository that already has a one-command setup renders a valid workflow and never sees
it. So the failure is invisible to a well-prepared repository and total for everyone else, which
inverts the intended onboarding gradient: init prints 40 files written and
Commit, push, open an issue, and comment /architect. That's the whole onboarding.

Suggested fix

Render the provision command into a block scalar, which is what checksRun (src/init.mjs:128)
already does for the checks list — including for a string containing ::error::. Roughly:

function provisionRun(command) {
  return command.split("\n").map((line) => `          ${line}`).join("\n");
}
run: |
{{PROVISION_RUN}}

That leaves the message byte-identical and only changes its YAML context. actionlint passes on
both templates afterwards. Happy to open a PR if the approach looks right.

Separately, and less certain: {{PROVISION_CMD}} is also interpolated into the agents'
--append-system-prompt "…" string (facility-crew.yml:252 and :273), inside shell double
quotes. A provision command containing a " would land there too. I have not verified whether
that actually breaks anything and am not claiming it does — flagging it only because it is the
same value in a second quoting context.

Environment

  • Facility main @ ca1c9df
  • facility --version reports 0.3.0
  • Node 22 / 24, macOS, GitHub-hosted ubuntu-latest runners
  • Validated with rhysd/actionlint

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/init.mjs, the packages/cli/templates/workflows/facility-crew.yml and facility-codex.yml templates, and the existing checksRun handling around src/init.mjs:128. Reproduce the no-provision case and a command containing ": ", then run actionlint on both generated workflows. Done means both agent workflows remain valid YAML while preserving the provision command text.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, node.js
Domain
ci-cd, cli, devops
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.