carlos / platform Public

run: Paul's follow-up copy (neutral example, --follow wording, two file-error fragments)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev e53bba58aea839319541bcecb3af24e7f8a75e60 parent d1d4e8f
3 files changed, +11 −9
  • approved_run_copy_test.go +5 −5
  • docs/site/cli.md +2 −2
  • docs/superpowers/plans/2026-10-08-carlos-run-copy.md +4 −2

CI passed — run details

diff --git a/approved_run_copy_test.go b/approved_run_copy_test.go
index 5f073cd8b..fd238e849 100644
--- a/approved_run_copy_test.go
+++ b/approved_run_copy_test.go
@@ -15,17 +15,17 @@ import (
// parser and checked with its helpers, so "applied" means the same thing in
// both gates:
//
-// - TestRunCopyRecordIsComplete: the deck names exactly RUN-C1 to RUN-C83;
+// - TestRunCopyRecordIsComplete: the deck names exactly RUN-C1 to RUN-C85;
// - TestRunBuiltCopyIsApproved: an id in runCopyBuilt is an approved row
// (a string reaches code only after Paul has approved it);
// - TestRunBuiltCopyIsApplied: a built row's text is in the file it names;
// - TestRunCopyHasNoEmDash.
const runCopyRecordPath = "docs/superpowers/plans/2026-10-08-carlos-run-copy.md"
-// runCopyIDs is the deck's inventory: RUN-C1 to RUN-C83, pinned.
+// runCopyIDs is the deck's inventory: RUN-C1 to RUN-C85, pinned.
var runCopyIDs = func() []string {
- ids := make([]string, 0, 83)
- for i := 1; i <= 83; i++ {
+ ids := make([]string, 0, 85)
+ for i := 1; i <= 85; i++ {
ids = append(ids, "RUN-C"+strconv.Itoa(i))
}
return ids
@@ -33,7 +33,7 @@ var runCopyIDs = func() []string {
// runCopyBuilt is every deck id whose text the code or docs now carry. The
// task that writes a row's text adds its id here in the same commit.
-var runCopyBuilt = []string{"RUN-C1", "RUN-C2", "RUN-C3", "RUN-C4", "RUN-C5", "RUN-C6", "RUN-C7", "RUN-C8", "RUN-C9", "RUN-C10", "RUN-C11", "RUN-C12", "RUN-C13", "RUN-C14", "RUN-C15", "RUN-C16", "RUN-C17", "RUN-C18", "RUN-C19", "RUN-C20", "RUN-C21", "RUN-C22", "RUN-C23", "RUN-C24", "RUN-C25", "RUN-C26", "RUN-C27", "RUN-C28", "RUN-C29", "RUN-C30", "RUN-C31", "RUN-C32", "RUN-C33", "RUN-C34", "RUN-C35", "RUN-C36", "RUN-C37", "RUN-C38", "RUN-C39", "RUN-C40", "RUN-C41", "RUN-C42", "RUN-C43", "RUN-C44", "RUN-C45", "RUN-C46", "RUN-C47", "RUN-C48", "RUN-C49", "RUN-C50", "RUN-C51", "RUN-C52", "RUN-C53", "RUN-C54", "RUN-C55", "RUN-C56", "RUN-C57", "RUN-C58", "RUN-C59", "RUN-C60", "RUN-C61", "RUN-C62", "RUN-C63", "RUN-C64", "RUN-C65", "RUN-C66", "RUN-C67", "RUN-C68", "RUN-C69", "RUN-C70", "RUN-C71", "RUN-C72", "RUN-C73", "RUN-C74", "RUN-C75", "RUN-C76", "RUN-C77", "RUN-C78", "RUN-C79", "RUN-C80", "RUN-C81", "RUN-C82", "RUN-C83"}
+var runCopyBuilt = []string{"RUN-C1", "RUN-C2", "RUN-C3", "RUN-C4", "RUN-C5", "RUN-C6", "RUN-C7", "RUN-C8", "RUN-C9", "RUN-C10", "RUN-C11", "RUN-C12", "RUN-C13", "RUN-C14", "RUN-C15", "RUN-C16", "RUN-C17", "RUN-C18", "RUN-C19", "RUN-C20", "RUN-C21", "RUN-C22", "RUN-C23", "RUN-C24", "RUN-C25", "RUN-C26", "RUN-C27", "RUN-C28", "RUN-C29", "RUN-C30", "RUN-C31", "RUN-C32", "RUN-C33", "RUN-C34", "RUN-C35", "RUN-C36", "RUN-C37", "RUN-C38", "RUN-C39", "RUN-C40", "RUN-C41", "RUN-C42", "RUN-C43", "RUN-C44", "RUN-C45", "RUN-C46", "RUN-C47", "RUN-C48", "RUN-C49", "RUN-C50", "RUN-C51", "RUN-C52", "RUN-C53", "RUN-C54", "RUN-C55", "RUN-C56", "RUN-C57", "RUN-C58", "RUN-C59", "RUN-C60", "RUN-C61", "RUN-C62", "RUN-C63", "RUN-C64", "RUN-C65", "RUN-C66", "RUN-C67", "RUN-C68", "RUN-C69", "RUN-C70", "RUN-C71", "RUN-C72", "RUN-C73", "RUN-C74", "RUN-C75", "RUN-C76", "RUN-C77", "RUN-C78", "RUN-C79", "RUN-C80", "RUN-C81", "RUN-C82", "RUN-C83", "RUN-C84", "RUN-C85"}
func mustParseRunRecord(t *testing.T) []copyRow {
t.Helper()
diff --git a/docs/site/cli.md b/docs/site/cli.md
index 33c702a59..2b69a00f6 100644
--- a/docs/site/cli.md
+++ b/docs/site/cli.md
@@ -474,14 +474,14 @@ which.
Runs one command of your app against one instance, as that instance: the same build, user, directories, database and environment it serves with. Output streams back to your terminal about a second behind, and carlos exits with the command's own status.
```sh
-carlos run --app titogo --instance acme.go.tito.io --file checkins.csv -- import checkins.csv
+carlos run --app shop --instance shop.example.com --file orders.csv -- import orders.csv
```
Any person who is a member of the account can run a command. A service credential cannot.
Each --file is uploaded with the request and placed, under its own name, in the directory CARLOS_RUN_DIR names. Together they can come to 64 MB. The directory is deleted when the run ends.
-The command runs for at most 30 minutes unless you pass --timeout, up to 6 hours. Ctrl-C cancels it on the box. A second Ctrl-C stops waiting, and the cancel still happens. If your terminal goes away the run carries on, and carlos run --follow picks its output up again. Output is kept until carlos has read all of it, and for 24 hours at most.
+The command runs for at most 30 minutes unless you pass --timeout, up to 6 hours. Ctrl-C cancels it on the box. A second Ctrl-C stops waiting, and the cancel still happens. If your terminal goes away the run carries on, and carlos run --app <app> --instance <host> --follow <id> picks its output up again. carlos prints that command when the run starts. Output is kept until carlos has read all of it, and for 24 hours at most.
A hibernating instance is woken first. A live one keeps serving, and the command opens the same database beside it. One run at a time per instance. carlos run needs the instance's box on the nested layout, and it is refused while the instance is moving.
diff --git a/docs/superpowers/plans/2026-10-08-carlos-run-copy.md b/docs/superpowers/plans/2026-10-08-carlos-run-copy.md
index bccd30d85..ea3915559 100644
--- a/docs/superpowers/plans/2026-10-08-carlos-run-copy.md
+++ b/docs/superpowers/plans/2026-10-08-carlos-run-copy.md
@@ -118,9 +118,9 @@ error; `<url>` a console URL; `<role>` a quoted role word.
| RUN-C68 | docs/site/cli.md | ### carlos run | approved |
| RUN-C69 | docs/site/cli.md | Runs one command of your app against one instance, as that instance: the same build, user, directories, database and environment it serves with. Output streams back to your terminal about a second behind, and carlos exits with the command's own status. | approved |
| RUN-C70 | docs/site/cli.md | Any person who is a member of the account can run a command. A service credential cannot. | approved |
-| RUN-C71 | docs/site/cli.md | carlos run --app titogo --instance acme.go.tito.io --file checkins.csv -- import checkins.csv | approved |
+| RUN-C71 | docs/site/cli.md | carlos run --app shop --instance shop.example.com --file orders.csv -- import orders.csv | approved |
| RUN-C72 | docs/site/cli.md | Each --file is uploaded with the request and placed, under its own name, in the directory CARLOS_RUN_DIR names. Together they can come to 64 MB. The directory is deleted when the run ends. | approved |
-| RUN-C73 | docs/site/cli.md | The command runs for at most 30 minutes unless you pass --timeout, up to 6 hours. Ctrl-C cancels it on the box. A second Ctrl-C stops waiting, and the cancel still happens. If your terminal goes away the run carries on, and carlos run --follow picks its output up again. Output is kept until carlos has read all of it, and for 24 hours at most. | approved |
+| RUN-C73 | docs/site/cli.md | The command runs for at most 30 minutes unless you pass --timeout, up to 6 hours. Ctrl-C cancels it on the box. A second Ctrl-C stops waiting, and the cancel still happens. If your terminal goes away the run carries on, and carlos run --app <app> --instance <host> --follow <id> picks its output up again. carlos prints that command when the run starts. Output is kept until carlos has read all of it, and for 24 hours at most. | approved |
| RUN-C74 | docs/site/cli.md | A hibernating instance is woken first. A live one keeps serving, and the command opens the same database beside it. One run at a time per instance. carlos run needs the instance's box on the nested layout, and it is refused while the instance is moving. | approved |
| RUN-C75 | docs/site/cli.md | carlos run exits with the command's own status, 128 plus the signal number when a signal ended it, 124 when it timed out, 125 when an instance stop or an agent restart interrupted it, 130 when you cancelled it, 3 when the box refused it or did not pick it up within 60 seconds, and 2 when the console refused it. | approved |
| RUN-C76 | docs/site/cli.md | Arguments are kept in the account's audit log, with who ran them. Never put a secret in an argument. Pass it in a --file, or keep it in the instance's environment. | approved |
@@ -129,3 +129,5 @@ error; `<url>` a console URL; `<role>` a quoted role word.
| RUN-C79 | docs/site/cli.md | this run's id | approved |
| RUN-C80 | docs/site/cli.md | a directory holding the files passed with --file, under their own names. Always set, even with no files. Deleted after the run | approved |
| RUN-C81 | docs/site/cli.md | Its arguments are exactly what followed --, after your binary. The platform adds nothing. It runs in the instance's data directory. On a cancel, a timeout or an instance stop it gets SIGTERM, then SIGKILL 20 seconds later. | approved |
+| RUN-C84 | run.go | not a regular file | approved |
+| RUN-C85 | run.go | the file changed while carlos was reading it | approved |