control-cli

A preserved method from https://github.com/cursor/plugins at f5bdd6826fd0, path cursor-team-kit/skills/control-cli, MIT. 17 of 109 source lines differ (16%), every difference claimed by an entry of the ledger with its reason. Entries: baseline-copies-2026-09-11, pull-2026-09-11, fold-2026-09-11.

  • harness 1
  • lifecycle 1
  • location 2
  • scope 1

Files

Every difference, as it stands

SKILL.md

---
---
harnesschangedbaseline-copies-2026-09-11

greenline renders its own frontmatter: quoted name and description, the description from the manifest override where one existed, no upstream activation flag

name: control-cli
name: "control-cli"
description: Build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI without external services. Use for CLI UX checks, startup regressions, memory leaks, hangs, prompt flows, or terminal demos.
description: "Build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI without external services. Use to drive a CLI end to end, reproduce a terminal bug, chase startup regressions, memory leaks, hangs, or prompt flows, or record a terminal demo."
---
---
 
 
# Control CLI
# Control CLI
 
 
scopechangedfold-2026-09-11

The skill's scope opens the body in its own voice: verify-this, diagnosing-bugs or product-description's phase 5 dispatches it when a verdict needs a transcript, timing or profile, the capture returns as evidence while the verdict stays with the requester, the repo's own harness comes first, and a non-interactive command needs no tmux session, PTY probe or fixture.

verify-this, diagnosing-bugs or product-description's phase 5 dispatches this method when its verdict needs a terminal transcript, a timing or a profile; the capture goes back to that stage as evidence, and the verdict stays there. Prefer the repo's own harness wherever one exists and assemble a new one only when none does. When the command under test is non-interactive, a plain captured invocation is the harness: no tmux session, no PTY probe, no fixture.
 
Use a repeatable local harness to exercise an interactive CLI instead of poking at it manually. First reuse the repo's own test/demo harness if it exists; otherwise assemble a temporary harness from standard local tools.
Use a repeatable local harness to exercise an interactive CLI instead of poking at it manually. First reuse the repo's own test/demo harness if it exists; otherwise assemble a temporary harness from standard local tools.
 
 
## What It Is Used For
## What It Is Used For
12 unchanged lines
 
 
- Reproducing CLI/TUI bugs with deterministic input.
- Reproducing CLI/TUI bugs with deterministic input.
- Verifying keyboard flows, prompts, interrupts, resize behavior, and terminal layout.
- Verifying keyboard flows, prompts, interrupts, resize behavior, and terminal layout.
- Capturing before/after transcripts for bug fixes.
- Capturing before/after transcripts for bug fixes.
- Profiling startup time, slow operations, hangs, or memory growth.
- Profiling startup time, slow operations, hangs, or memory growth.
- Recording a short terminal demo when output is easier to show than explain.
- Recording a short terminal demo when output is easier to show than explain.
 
 
## Harness Loop
## Harness Loop
 
 
1. Identify the command under test and the smallest reproducible workspace.
1. Identify the command under test and the smallest reproducible workspace.
2. Discover existing local harnesses: package scripts, e2e tests, demo recorders, expect scripts, or PTY helpers.
2. Discover existing local harnesses: package scripts, e2e tests, demo recorders, expect scripts, or PTY helpers.
3. If no harness exists, launch the CLI in an isolated terminal session with deterministic env vars.
3. If no harness exists, launch the CLI in an isolated terminal session with deterministic env vars.
4. Capture the current screen before interacting.
4. Capture the current screen before interacting.
5. Send one action at a time: text, Enter, arrows, Escape, Ctrl-C, resize.
5. Send one action at a time: text, Enter, arrows, Escape, Ctrl-C, resize.
6. Wait for a concrete screen pattern or prompt before the next action.
6. Wait for a concrete screen pattern or prompt before the next action.
locationchangedfold-2026-09-11

Upstream's /tmp becomes greenline's scratch home in place: the harness and its captures live in .greenline/tmp/control-cli/ unless the repo has its own harness, are promoted to the owner's evidence home when the requesting verdict relies on them because the scratch directory is not durable proof, and a read-only request keeps them outside the repository.

7. Save the transcript and any profile artifacts.
7. Save the transcript and any profile artifacts under `.greenline/tmp/control-cli/`, and promote the ones the requesting verdict relies on to the owner's evidence home.
8. Kill the session cleanly.
8. Kill the session cleanly.
 
 
## Harness Options
## Harness Options
74 unchanged lines
 
 
- Repo-native harness: prefer checked-in scripts because they know the app's startup, env, and prompts.
- Repo-native harness: prefer checked-in scripts because they know the app's startup, env, and prompts.
- `tmux`: managed sessions, `capture-pane`, `send-keys`, attach/detach.
- `tmux`: managed sessions, `capture-pane`, `send-keys`, attach/detach.
- PTY probe: use a short Python, Node, or Expect script when tmux is unavailable.
- PTY probe: use a short Python, Node, or Expect script when tmux is unavailable.
- Runtime inspector: use Node or Bun inspector for CPU profiles, heap snapshots, and live evaluation.
- Runtime inspector: use Node or Bun inspector for CPU profiles, heap snapshots, and live evaluation.
- Terminal recorder: use repo-local demo tools or asciinema-compatible tools when the user asks for a demo.
- Terminal recorder: use repo-local demo tools or asciinema-compatible tools when the user asks for a demo.
 
 
## Minimal tmux Harness
## Minimal tmux Harness
 
 
```bash
```bash
SESSION="cli-harness-$(date +%s)"
SESSION="cli-harness-$(date +%s)"
tmux new-session -d -s "$SESSION" -- <command-under-test>
tmux new-session -d -s "$SESSION" -- <command-under-test>
tmux capture-pane -pt "$SESSION"
tmux capture-pane -pt "$SESSION"
tmux send-keys -t "$SESSION" "help" Enter
tmux send-keys -t "$SESSION" "help" Enter
tmux capture-pane -pt "$SESSION"
tmux capture-pane -pt "$SESSION"
tmux kill-session -t "$SESSION"
tmux kill-session -t "$SESSION"
```
```
 
 
For Node CLIs:
For Node CLIs:
 
 
```bash
```bash
NODE_OPTIONS="--inspect=127.0.0.1:0" tmux new-session -d -s "$SESSION" -- <node-cli-command>
NODE_OPTIONS="--inspect=127.0.0.1:0" tmux new-session -d -s "$SESSION" -- <node-cli-command>
```
```
 
 
Read the terminal output to find the inspector URL, then use Chrome DevTools-compatible tooling if profiling is needed.
Read the terminal output to find the inspector URL, then use Chrome DevTools-compatible tooling if profiling is needed.
 
 
## Minimal PTY Harness
## Minimal PTY Harness
 
 
Use a PTY script when you need deterministic waits in a repo that does not have tmux or a demo harness. Keep it temporary unless the user asks to add a reusable test.
Use a PTY script when you need deterministic waits in a repo that does not have tmux or a demo harness. Keep it temporary unless the user asks to add a reusable test.
 
 
```python
```python
import os
import os
import pty
import pty
import select
import select
import subprocess
import subprocess
import time
import time
 
 
master_fd, slave_fd = pty.openpty()
master_fd, slave_fd = pty.openpty()
proc = subprocess.Popen(
proc = subprocess.Popen(
["<command>", "<arg>"],
["<command>", "<arg>"],
stdin=slave_fd,
stdin=slave_fd,
stdout=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
stderr=slave_fd,
close_fds=True,
close_fds=True,
)
)
os.close(slave_fd)
os.close(slave_fd)
 
 
deadline = time.time() + 30
deadline = time.time() + 30
buffer = b""
buffer = b""
while time.time() < deadline:
while time.time() < deadline:
ready, _, _ = select.select([master_fd], [], [], 0.25)
ready, _, _ = select.select([master_fd], [], [], 0.25)
if not ready:
if not ready:
continue
continue
chunk = os.read(master_fd, 4096)
chunk = os.read(master_fd, 4096)
buffer += chunk
buffer += chunk
if b"<ready text>" in buffer:
if b"<ready text>" in buffer:
os.write(master_fd, b"help\n")
os.write(master_fd, b"help\n")
break
break
 
 
print(buffer.decode(errors="replace"))
print(buffer.decode(errors="replace"))
proc.terminate()
proc.terminate()
os.close(master_fd)
os.close(master_fd)
```
```
 
 
If the CLI needs richer terminal control, use `pty.fork()` or an existing PTY library.
If the CLI needs richer terminal control, use `pty.fork()` or an existing PTY library.
 
 
## Profiling Recipes
## Profiling Recipes
 
 
- Startup regression: capture baseline and treatment startup timings under the same machine, env, and command.
- Startup regression: capture baseline and treatment startup timings under the same machine, env, and command.
- Slow operation: start a CPU profile, perform the operation, stop the profile, and compare top self-time functions.
- Slow operation: start a CPU profile, perform the operation, stop the profile, and compare top self-time functions.
- Memory leak: force GC if available, take a heap snapshot, perform the operation repeatedly, force GC again, and take another snapshot.
- Memory leak: force GC if available, take a heap snapshot, perform the operation repeatedly, force GC again, and take another snapshot.
- Hang: capture the screen, active handles/resources, and a stack/CPU sample before interrupting.
- Hang: capture the screen, active handles/resources, and a stack/CPU sample before interrupting.
 
 
## Guardrails
## Guardrails
 
 
- Prefer deterministic waits over sleeps. If you must sleep, explain why.
- Prefer deterministic waits over sleeps. If you must sleep, explain why.
- Do not send credentials or destructive commands into a controlled session.
- Do not send credentials or destructive commands into a controlled session.
locationchangedfold-2026-09-11

Upstream's /tmp becomes greenline's scratch home in place: the harness and its captures live in .greenline/tmp/control-cli/ unless the repo has its own harness, are promoted to the owner's evidence home when the requesting verdict relies on them because the scratch directory is not durable proof, and a read-only request keeps them outside the repository.

- Keep the harness in `/tmp` unless the repo already has a testing/demo harness.
- Keep the harness in `.greenline/tmp/control-cli/` unless the repo already has a testing/demo harness. That directory is not durable proof: promote a relied-on instrument and its capture to the owner's evidence home before closing. A read-only request keeps its instrument and capture outside the repository.
- Do not hard-code paths from another repository. Adapt commands to the current repo's scripts and runtime.
- Do not hard-code paths from another repository. Adapt commands to the current repo's scripts and runtime.
- Clean up tmux sessions, temp dirs, inspector processes, and demo artifacts unless the user asks to keep them.
- Clean up tmux sessions, temp dirs, inspector processes, and demo artifacts unless the user asks to keep them.
lifecyclechangedfold-2026-09-11

The Handoff section (ADR 0039) names what this support skill consumes, the evidence it produces, its scratch and promoted homes, and the stages it returns to, so the chain closes.

 
## Handoff
 
Consumes: the command under test and the question the requesting stage needs answered
Produces: a transcript, timing or profile with the instrument that made it, as evidence for the requester's verdict
Evidence at: .greenline/tmp/control-cli/, promoted to .greenline/work/evidence/<work-id>/ or .greenline/ledger/evidence/<contribution>/ when the result relies on it
Returns to: verify-this or diagnosing-bugs, or product-description's phase 5

The timeline

Each entry that touched this method, with the differences it claimed as they stood at its commit, read from the repository's history.

2026-09-11 baseline-copies-2026-09-11

the cutover to an edited copy (ADR 0039): the composed output written as the copy, every difference from upstream claimed with the reason of the overlay that produced it

SKILL.md

harnesschangedbaseline-copies-2026-09-11

greenline renders its own frontmatter: quoted name and description, the description from the manifest override where one existed, no upstream activation flag

name: control-cli
name: "control-cli"
description: Build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI without external services. Use for CLI UX checks, startup regressions, memory leaks, hangs, prompt flows, or terminal demos.
description: "Build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI without external services. Use to drive a CLI end to end, reproduce a terminal bug, chase startup regressions, memory leaks, hangs, or prompt flows, or record a terminal demo."
lifecyclechangedbaseline-copies-2026-09-11

greenline prelude, to fold: prefer the repository's own harness; scratch under .greenline/tmp/control-cli/ instead of /tmp

**greenline prelude: the cheapest harness that answers the question.** Prefer the repo's own harness wherever one exists; assemble a new one only when none does. When the command under test is non-interactive, a plain captured invocation is the harness: no tmux session, no PTY probe, no fixture.
 
Replace the Guardrails instruction “Keep the harness in /tmp” for an authorized
workspace write: put a new disposable instrument in `.greenline/tmp/control-cli/`.
An existing repository testing/demo harness is still preferred. A read-only
request keeps its temporary instrument and capture outside the repository.
Promote relied-on instruments and results to the owner's evidence home before
closing; the temporary location is not durable proof.
 
lifecyclechangedbaseline-copies-2026-09-11

greenline completion, to fold: the transcript is evidence for the requesting diagnosis, not its own verdict; promote relied-on instruments to the owner's evidence home

 
 
## greenline completion: the transcript is evidence
 
A transcript, timing, or profile is evidence for the requesting diagnosis or verification, not its own verdict. Reuse the shared work and ledger conventions. Retain relied-on instruments beside results in the owner's evidence home. Disposable probes can use `.greenline/tmp/control-cli/` during authorized writes; a read-only task keeps capture outside the repository and reports its result without a new repository account. Return to the method that requested the instrument.

2026-09-11 pull-2026-09-11

pin advance to f5bdd68: upstream moved with no change under the vendored paths

2026-09-11 fold-2026-09-11

The prelude and completion are folded into the body: the scope opens the method, the OS temp path in the guardrail and the save step become greenline's scratch home with promotion, and a Handoff section returns the transcript as evidence to the requesting stage.

SKILL.md

scopechangedfold-2026-09-11

The skill's scope opens the body in its own voice: verify-this, diagnosing-bugs or product-description's phase 5 dispatches it when a verdict needs a transcript, timing or profile, the capture returns as evidence while the verdict stays with the requester, the repo's own harness comes first, and a non-interactive command needs no tmux session, PTY probe or fixture.

verify-this, diagnosing-bugs or product-description's phase 5 dispatches this method when its verdict needs a terminal transcript, a timing or a profile; the capture goes back to that stage as evidence, and the verdict stays there. Prefer the repo's own harness wherever one exists and assemble a new one only when none does. When the command under test is non-interactive, a plain captured invocation is the harness: no tmux session, no PTY probe, no fixture.
 
locationchangedfold-2026-09-11

Upstream's /tmp becomes greenline's scratch home in place: the harness and its captures live in .greenline/tmp/control-cli/ unless the repo has its own harness, are promoted to the owner's evidence home when the requesting verdict relies on them because the scratch directory is not durable proof, and a read-only request keeps them outside the repository.

7. Save the transcript and any profile artifacts.
7. Save the transcript and any profile artifacts under `.greenline/tmp/control-cli/`, and promote the ones the requesting verdict relies on to the owner's evidence home.
locationchangedfold-2026-09-11

Upstream's /tmp becomes greenline's scratch home in place: the harness and its captures live in .greenline/tmp/control-cli/ unless the repo has its own harness, are promoted to the owner's evidence home when the requesting verdict relies on them because the scratch directory is not durable proof, and a read-only request keeps them outside the repository.

- Keep the harness in `/tmp` unless the repo already has a testing/demo harness.
- Keep the harness in `.greenline/tmp/control-cli/` unless the repo already has a testing/demo harness. That directory is not durable proof: promote a relied-on instrument and its capture to the owner's evidence home before closing. A read-only request keeps its instrument and capture outside the repository.
lifecyclechangedfold-2026-09-11

The Handoff section (ADR 0039) names what this support skill consumes, the evidence it produces, its scratch and promoted homes, and the stages it returns to, so the chain closes.

 
## Handoff
 
Consumes: the command under test and the question the requesting stage needs answered
Produces: a transcript, timing or profile with the instrument that made it, as evidence for the requester's verdict
Evidence at: .greenline/tmp/control-cli/, promoted to .greenline/work/evidence/<work-id>/ or .greenline/ledger/evidence/<contribution>/ when the result relies on it
Returns to: verify-this or diagnosing-bugs, or product-description's phase 5