Skip to content

Commit d7a928b

Browse files
authored
fix(agents): add --no-interactive to validate commands in agent workflows (Fission-AI#494)
AI agents following OpenSpec workflows would hit interactive prompts when running `openspec validate` because the commands in AGENTS.md and slash command templates didn't include the --no-interactive flag. This caused hangs in LLM tool execution since agents run in pseudo-TTY environments where process.stdin.isTTY returns true, triggering interactive mode. Fixes Fission-AI#492
1 parent 07dd634 commit d7a928b

4 files changed

Lines changed: 27 additions & 25 deletions

File tree

openspec/AGENTS.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Instructions for AI coding assistants using OpenSpec for spec-driven development
99
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
1010
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
1111
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
12-
- Validate: `openspec validate [change-id] --strict` and fix issues
12+
- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues
1313
- Request approval: Do not start implementation until proposal is approved
1414

1515
## Three-Stage Workflow
@@ -44,7 +44,7 @@ Skip proposal for:
4444
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
4545
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
4646
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
47-
4. Run `openspec validate <id> --strict` and resolve any issues before sharing the proposal.
47+
4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.
4848

4949
### Stage 2: Implementing Changes
5050
Track these steps as TODOs and complete them one by one.
@@ -61,7 +61,7 @@ After deployment, create separate PR to:
6161
- Move `changes/[name]/``changes/archive/YYYY-MM-DD-[name]/`
6262
- Update `specs/` if capabilities changed
6363
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
64-
- Run `openspec validate --strict` to confirm the archived change passes checks
64+
- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks
6565

6666
## Before Any Task
6767

@@ -108,7 +108,7 @@ openspec validate # Bulk validation mode
108108

109109
# Debugging
110110
openspec show [change] --json --deltas-only
111-
openspec validate [change] --strict
111+
openspec validate [change] --strict --no-interactive
112112
```
113113

114114
### Command Flags
@@ -160,6 +160,8 @@ New request?
160160

161161
2. **Write proposal.md:**
162162
```markdown
163+
# Change: [Brief description of change]
164+
163165
## Why
164166
[1-2 sentences on problem/opportunity]
165167

@@ -304,7 +306,7 @@ Example for RENAMED:
304306

305307
```bash
306308
# Always use strict mode for comprehensive checks
307-
openspec validate [change] --strict
309+
openspec validate [change] --strict --no-interactive
308310

309311
# Debug delta parsing
310312
openspec show [change] --json | jq '.deltas'
@@ -341,7 +343,7 @@ Users MUST provide a second factor during login.
341343
EOF
342344

343345
# 4) Validate
344-
openspec validate $CHANGE --strict
346+
openspec validate $CHANGE --strict --no-interactive
345347
```
346348

347349
## Multi-Capability Example
@@ -447,7 +449,7 @@ Only add complexity with:
447449
```bash
448450
openspec list # What's in progress?
449451
openspec show [item] # View details
450-
openspec validate --strict # Is it correct?
452+
openspec validate --strict --no-interactive # Is it correct?
451453
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
452454
```
453455

src/core/templates/agents-template.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Instructions for AI coding assistants using OpenSpec for spec-driven development
99
- Pick a unique \`change-id\`: kebab-case, verb-led (\`add-\`, \`update-\`, \`remove-\`, \`refactor-\`)
1010
- Scaffold: \`proposal.md\`, \`tasks.md\`, \`design.md\` (only if needed), and delta specs per affected capability
1111
- Write deltas: use \`## ADDED|MODIFIED|REMOVED|RENAMED Requirements\`; include at least one \`#### Scenario:\` per requirement
12-
- Validate: \`openspec validate [change-id] --strict\` and fix issues
12+
- Validate: \`openspec validate [change-id] --strict --no-interactive\` and fix issues
1313
- Request approval: Do not start implementation until proposal is approved
1414
1515
## Three-Stage Workflow
@@ -44,7 +44,7 @@ Skip proposal for:
4444
1. Review \`openspec/project.md\`, \`openspec list\`, and \`openspec list --specs\` to understand current context.
4545
2. Choose a unique verb-led \`change-id\` and scaffold \`proposal.md\`, \`tasks.md\`, optional \`design.md\`, and spec deltas under \`openspec/changes/<id>/\`.
4646
3. Draft spec deltas using \`## ADDED|MODIFIED|REMOVED Requirements\` with at least one \`#### Scenario:\` per requirement.
47-
4. Run \`openspec validate <id> --strict\` and resolve any issues before sharing the proposal.
47+
4. Run \`openspec validate <id> --strict --no-interactive\` and resolve any issues before sharing the proposal.
4848
4949
### Stage 2: Implementing Changes
5050
Track these steps as TODOs and complete them one by one.
@@ -61,7 +61,7 @@ After deployment, create separate PR to:
6161
- Move \`changes/[name]/\` → \`changes/archive/YYYY-MM-DD-[name]/\`
6262
- Update \`specs/\` if capabilities changed
6363
- Use \`openspec archive <change-id> --skip-specs --yes\` for tooling-only changes (always pass the change ID explicitly)
64-
- Run \`openspec validate --strict\` to confirm the archived change passes checks
64+
- Run \`openspec validate --strict --no-interactive\` to confirm the archived change passes checks
6565
6666
## Before Any Task
6767
@@ -108,7 +108,7 @@ openspec validate # Bulk validation mode
108108
109109
# Debugging
110110
openspec show [change] --json --deltas-only
111-
openspec validate [change] --strict
111+
openspec validate [change] --strict --no-interactive
112112
\`\`\`
113113
114114
### Command Flags
@@ -306,7 +306,7 @@ Example for RENAMED:
306306
307307
\`\`\`bash
308308
# Always use strict mode for comprehensive checks
309-
openspec validate [change] --strict
309+
openspec validate [change] --strict --no-interactive
310310
311311
# Debug delta parsing
312312
openspec show [change] --json | jq '.deltas'
@@ -343,7 +343,7 @@ Users MUST provide a second factor during login.
343343
EOF
344344
345345
# 4) Validate
346-
openspec validate $CHANGE --strict
346+
openspec validate $CHANGE --strict --no-interactive
347347
\`\`\`
348348
349349
## Multi-Capability Example
@@ -449,7 +449,7 @@ Only add complexity with:
449449
\`\`\`bash
450450
openspec list # What's in progress?
451451
openspec show [item] # View details
452-
openspec validate --strict # Is it correct?
452+
openspec validate --strict --no-interactive # Is it correct?
453453
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
454454
\`\`\`
455455

src/core/templates/slash-command-templates.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const proposalSteps = `**Steps**
1515
4. Capture architectural reasoning in \`design.md\` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
1616
5. Draft spec deltas in \`changes/<id>/specs/<capability>/spec.md\` (one folder per capability) using \`## ADDED|MODIFIED|REMOVED Requirements\` with at least one \`#### Scenario:\` per requirement and cross-reference related capabilities when relevant.
1717
6. Draft \`tasks.md\` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
18-
7. Validate with \`openspec validate <id> --strict\` and resolve every issue before sharing the proposal.`;
18+
7. Validate with \`openspec validate <id> --strict --no-interactive\` and resolve every issue before sharing the proposal.`;
1919

2020

2121
const proposalReferences = `**Reference**
@@ -43,7 +43,7 @@ const archiveSteps = `**Steps**
4343
2. Validate the change ID by running \`openspec list\` (or \`openspec show <id>\`) and stop if the change is missing, already archived, or otherwise not ready to archive.
4444
3. Run \`openspec archive <id> --yes\` so the CLI moves the change and applies spec updates without prompts (use \`--skip-specs\` only for tooling-only work).
4545
4. Review the command output to confirm the target specs were updated and the change landed in \`changes/archive/\`.
46-
5. Validate with \`openspec validate --strict\` and inspect with \`openspec show <id>\` if anything looks off.`;
46+
5. Validate with \`openspec validate --strict --no-interactive\` and inspect with \`openspec show <id>\` if anything looks off.`;
4747

4848
const archiveReferences = `**Reference**
4949
- Use \`openspec list\` to confirm change IDs before archiving.

test/core/update.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Old slash content
133133
expect(updated).toContain('name: OpenSpec: Proposal');
134134
expect(updated).toContain('**Guardrails**');
135135
expect(updated).toContain(
136-
'Validate with `openspec validate <id> --strict`'
136+
'Validate with `openspec validate <id> --strict --no-interactive`'
137137
);
138138
expect(updated).not.toContain('Old slash content');
139139

@@ -317,7 +317,7 @@ Old slash content
317317
expect(updated).toContain('# OpenSpec: Proposal');
318318
expect(updated).toContain('**Guardrails**');
319319
expect(updated).toContain(
320-
'Validate with `openspec validate <id> --strict`'
320+
'Validate with `openspec validate <id> --strict --no-interactive`'
321321
);
322322
expect(updated).not.toContain('Old slash content');
323323

@@ -1007,7 +1007,7 @@ Old slash content
10071007
expect(updated).toContain('name: OpenSpec: Proposal');
10081008
expect(updated).toContain('**Guardrails**');
10091009
expect(updated).toContain(
1010-
'Validate with `openspec validate <id> --strict`'
1010+
'Validate with `openspec validate <id> --strict --no-interactive`'
10111011
);
10121012
expect(updated).not.toContain('Old slash content');
10131013

@@ -1085,7 +1085,7 @@ Old slash content
10851085
expect(updated).toContain('name: OpenSpec: Proposal');
10861086
expect(updated).toContain('**Guardrails**');
10871087
expect(updated).toContain(
1088-
'Validate with `openspec validate <id> --strict`'
1088+
'Validate with `openspec validate <id> --strict --no-interactive`'
10891089
);
10901090
expect(updated).not.toContain('Old slash content');
10911091

@@ -1163,7 +1163,7 @@ Old body
11631163
expect(updated).toContain('argument-hint: old-hint');
11641164
expect(updated).toContain('**Guardrails**');
11651165
expect(updated).toContain(
1166-
'Validate with `openspec validate <id> --strict`'
1166+
'Validate with `openspec validate <id> --strict --no-interactive`'
11671167
);
11681168
expect(updated).not.toContain('Old body');
11691169

@@ -1204,7 +1204,7 @@ Old slash content
12041204
expect(updated).toContain('name: OpenSpec: Proposal');
12051205
expect(updated).toContain('**Guardrails**');
12061206
expect(updated).toContain(
1207-
'Validate with `openspec validate <id> --strict`'
1207+
'Validate with `openspec validate <id> --strict --no-interactive`'
12081208
);
12091209
expect(updated).not.toContain('Old slash content');
12101210

@@ -1244,7 +1244,7 @@ Old body
12441244
expect(updated).toContain('# OpenSpec: Proposal');
12451245
expect(updated).toContain('**Guardrails**');
12461246
expect(updated).toContain(
1247-
'Validate with `openspec validate <id> --strict`'
1247+
'Validate with `openspec validate <id> --strict --no-interactive`'
12481248
);
12491249
expect(updated).not.toContain('Old body');
12501250

@@ -1431,7 +1431,7 @@ More instructions after.`;
14311431
expect(updated).toContain('## Custom Intro Title');
14321432
expect(updated).toContain('Footer stays');
14331433
expect(updated).not.toContain('Old body');
1434-
expect(updated).toContain('Validate with `openspec validate <id> --strict`');
1434+
expect(updated).toContain('Validate with `openspec validate <id> --strict --no-interactive`');
14351435
});
14361436

14371437
it('should handle configurator errors gracefully for CoStrict', async () => {
@@ -1487,7 +1487,7 @@ More instructions after.`;
14871487
expect(updated).toContain('## Custom Intro Title');
14881488
expect(updated).toContain('Footer stays');
14891489
expect(updated).not.toContain('Old body');
1490-
expect(updated).toContain('Validate with `openspec validate <id> --strict`');
1490+
expect(updated).toContain('Validate with `openspec validate <id> --strict --no-interactive`');
14911491
});
14921492

14931493
it('should not create missing Windsurf workflows on update', async () => {

0 commit comments

Comments
 (0)