Requirements: split /the-loop:init into /init, /init-cli and /init-gateway
Phase 1 of 3 (requirements → design → tasks). Tier 3 (
human-approves-pr): the change rewrites command prose, the onboarding reference and the user docs. It adds no CLI verb, changes no schema and moves no file a project already has.
Introduction
Issue #514, from the owner: /the-loop:init does too much for most of the repositories it runs in.
Today one command does three jobs. It walks the harness config (the agent's per-repo file), then the CLI config (the operator's daemon file), then, if asked, the gateway config. Only one repository in a deployment is the operator repository, the one that holds the daemon's config. Every other repository that uses the-loop needs just the plugin, .the-loop/harness-config.yaml and the docs/ trees. Running /init there still opens with "where will the daemon run?" and "how much should it do unattended?". Those questions do not apply to that repository, and a user cannot skip them without knowing they are optional.
The ask: the plain /init does the repository part only. CLI setup moves to a separate /init-cli, and gateway setup to /init-gateway.
Each of the three commands is idempotent, non-clobbering and supports --dry-run and --defaults, the same contract /init keeps today. Each one walks its own schema's x-onboarding groups with the procedure in the skill's reference/onboarding.md.
Requirements
Requirement 1 — /the-loop:init initializes the repository only
User story: As a developer adding the-loop to a repository that just uses it, I want /init to set up only what that repository needs, so that I am not asked about a daemon, Slack or a gateway I will never run from here.
Acceptance criteria (EARS)
- WHEN
/the-loop:initruns THEN the system SHALL scaffold, where missing,.the-loop/harness-config.yaml,.the-loop/manifest.yaml,.the-loop/collaborators.yamland the docs trees (docs/architecture/architecture.md,docs/decisions/decisions.md,docs/specs/,docs/capabilities/,docs/learnings/learnings.md), as it does today. - WHEN
/the-loop:initruns THEN the system SHALL walk the harness-config onboarding (harness-config.schema.json→x-onboarding.groups) and SHALL NOT ask the deployment-shape question, the autonomy-profile question, the CLI-config location question, or any CLI-config, Slack, Jira or gateway question. - WHEN
/the-loop:initruns THEN the system SHALL NOT create or modify any CLI config (.the-loop/cli-config.yamlor~/.the-loop/cli-config.yaml),slack-app-manifest.jsonorgateway-config.yaml. - WHEN
/the-loop:initruns on a GitHub-ticketed repository THEN the system SHALL create the missingloop:<phase>labels, as it does today. These labels describe the repository's own tickets, so they stay with/init. - WHEN
/the-loop:initruns THEN the system SHALL keep wiring local hooks and CI parity only where the project has none of its own, as it does today. - WHEN
/the-loop:initfinishes THEN its report SHALL say that no CLI or gateway setup was done, and SHALL name/the-loop:init-cliand/the-loop:init-gatewayas the commands for that, with one line on who needs each. - IF a CLI config already exists in the repository WHEN
/the-loop:initruns THEN the system SHALL leave it untouched and SHALL mention it in the report under skipped, pointing to/the-loop:init-clifor any change.
Requirement 2 — /the-loop:init-cli initializes the operator's CLI config
User story: As the operator who runs the-loop's daemon, I want a dedicated command for the CLI config, so that the daemon's setup is a deliberate step I take once, in the operator repository or my home directory.
Acceptance criteria (EARS)
- The system SHALL ship a
/the-loop:init-clicommand (commands/init-cli.md) for every harness that shipscommands/. - WHEN
/the-loop:init-cliruns THEN the system SHALL carry out what today's/initsteps 3, 4 (minus the gateway-config part), 5 and 10 do for the CLI config: the deployment shape and autonomy profile, the location question (repository or~/.the-loop/), thecli-config.schema.jsonwalk (including thegatewayingress block for an instance that reads from a gateway), Slack, Jira, and the credential preflight for the variables the CLI config names. - WHEN
/the-loop:init-cliruns THEN the system SHALL create therouting.autoExecuteLabelsentries in the repositories the config routes, where routing was enabled and the labels are missing. - WHEN
/the-loop:init-cliruns THEN the system SHALL NOT require.the-loop/harness-config.yamlto exist and SHALL NOT create or modify it, the docs trees or the phase labels. - WHEN
/the-loop:init-cliwrites a CLI config THEN the system SHALL validate it against the plugin'scli-config.schema.json, read frommanifest.schemasDiron disk. - WHEN
/the-loop:init-clifinishes THEN its report SHALL name the autonomy profile applied (or say plainly that no automation is enabled), list every credential still missing by variable name, and name/the-loop:init-gatewaywhen the user said this machine runs the gateway.
Requirement 3 — /the-loop:init-gateway initializes a gateway host
User story: As the person who runs a the-loop gateway for several instances, I want its config set up by its own command, so that gateway setup is neither buried inside CLI onboarding nor offered to people who will never run one.
Acceptance criteria (EARS)
- The system SHALL ship a
/the-loop:init-gatewaycommand (commands/init-gateway.md). - WHEN
/the-loop:init-gatewayruns THEN the system SHALL establishgateway-config.yamlby walkinggateway-config.schema.json→x-onboarding.groups, scaffolded fromtemplates/gateway-config.yamlwith the modeline kept as the first line. - WHEN
/the-loop:init-gatewayruns THEN the system SHALL ask where the file lives (beside a CLI config in this repository, or~/.the-loop/) and SHALL NOT assume either. - WHEN
/the-loop:init-gatewaywrites the file THEN the system SHALL validate it against the plugin'sgateway-config.schema.jsonand SHALL run the credential preflight (presence only) for every secret variable the file names. - WHEN
/the-loop:init-gatewayruns THEN the system SHALL NOT create or modify the harness config, the CLI config, the docs trees or any label.
Requirement 4 — the three commands share one contract
User story: As a user of any of the three commands, I want them to behave the same way, so that learning one teaches me the others.
Acceptance criteria (EARS)
- Each of
/init,/init-cliand/init-gatewaySHALL accept--dry-run(print the report, write nothing, ask nothing) and--defaults(ask nothing, default everything, list gaps under needs-user). - Each SHALL be idempotent and non-clobbering per
.the-loop/manifest.yaml: it creates only what is missing and never overwrites a user-owned file. - On a re-run, each SHALL raise only gaps (empty required keys,
# TODO: verifylines, keys added by an upgrade) and SHALL NOT re-ask what is already established. - Each SHALL end with the created / skipped / drifted / needs-user report and the next action.
Requirement 5 — docs and references move with the split
User story: As a reader of the-loop's docs, I want every page that describes /init to describe the new split, so that no page tells me /init will ask about the daemon.
Acceptance criteria (EARS)
- WHEN this work item merges THEN the skill (
SKILL.md§ Commands,reference/onboarding.md),docs/reference/commands.md,docs/guide/onboarding.md,docs/guide/quickstart.md,docs/guide/installation.md,docs/guide/gateway.md, anddocs/guide/slack.mdSHALL describe the three commands wherever they now describe CLI or gateway setup as part of/init. - WHEN this work item merges THEN
.the-loop/manifest.yaml's optionalcli-config.yamlandslack-app-manifest.jsonentries SHALL name/the-loop:init-clias the command that scaffolds them. - WHEN this work item merges THEN the affected capability docs (
distribution.mdat least) SHALL state the new behaviour with a history row for issue-514. - WHEN this work item merges THEN
/the-loop:upgrade-the-loopSHALL point to the command that owns a missing file (/init-clifor a CLI config,/init-gatewayfor a gateway config) wherever it now says/init.
Non-functional requirements
- No behaviour lost. Every step of today's
/initlands in exactly one of the three commands. Design records that mapping step by step. - No new code path in the CLI. The commands are agent prose. The onboarding schemas and their
x-onboardinggroups stay as they are; the schema-consistency tests (test_onboarding_schema.py,test_manifest_schemas.py) keep passing unchanged. - Discoverability. A user who runs only
/initis told the other two exist, and what each is for, in the final report (R1.6).
Security considerations
No new attack surface. The change splits existing agent instructions across three commands. It adds no network call, no CLI verb, no token handling and no new input.
- Actors & trust: the user running the command (trusted, local); the repository's existing files (read, never trusted as instructions); the shipped schemas and templates (the plugin's, read from disk).
- Trust boundaries & data: credentials are handled exactly as today. They are referenced by environment-variable name in the configs, and their presence is reported only by
/init-cliand/init-gateway. The split narrows exposure:/initno longer touches anything credential-bearing. - Abuse cases (EARS):
- WHEN any of the three commands runs the credential preflight THEN the system SHALL report presence only, never a value, prefix, length or hash, and SHALL NOT write a credential into any file.
- WHEN
/the-loop:initruns THEN the system SHALL NOT read, print or check any credential variable. - WHEN a command validates a config THEN the system SHALL read the schema from the plugin on disk and SHALL NOT fetch one over the network.
- Fail closed: IF the schema a command needs cannot be read from the plugin THEN that command SHALL stop before writing its config and report the missing schema, rather than write an unvalidated file.
Out of scope
- Changing any config schema, template or
x-onboardinggroup. - A CLI verb (
the-loop init …). These remain slash commands. - Splitting
/the-loop:upgrade-the-loop. It keeps reconciling every manifest entry, and only its pointers change (R5.4). - A Codex slash-command surface. Codex ships
skills/only today, and this item does not change that.
Open questions
Assumed defaults, open to change at the requirements gate:
collaborators.yamlstays with/init. The issue names only the harness config, but the skill readscollaborators.yamlfor people and approver roles in every repository. It is a per-repository file, not an operator one.loop:<phase>labels stay with/init, and therouting.autoExecuteLabelsarming labels move to/init-cli. Phase labels describe a repository's tickets, while arming labels exist only because a daemon routes that repository.- No
--only-harnessflag. The issue's first bullet asks for "an option" and its later bullets make that the default of/init. Making it the default needs no flag. /init-clidoes not run/initfirst. The CLI config is independent of any repository (decision-032), so the operator repository runs both commands, and no other repository runs/init-cli.
Review comments
Appended by the-loop's
record-feedbackhook when a human gate approves with comments (issue-109). Append-only and attributed: an approval never silently discards a reviewer's suggestions, and the feedback travels with the document it concerns rather than living in a side-channel tracker.
2026-10-20 — approved
@MadaraUchiha-314 wrote:
approved