cli: std/cli (CLI slice 1) #123

Closed
opened 2026-10-05 21:07:23 +00:00 by orion · 4 comments
Collaborator

Context

Commands, flags, options, positional arguments, help and errors declared once.

Source

Acceptance criteria

  • Typed options or a decoded type, decided per section 2
  • Tests with argument lists

Dependencies

None known.

Moved from the planning lists of the docs; the design record stays the specification.

## Context Commands, flags, options, positional arguments, help and errors declared once. ## Source - [CLI.md slice 1](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/CLI.md#L47) - [CLI.md section 2](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/CLI.md#L37) ## Acceptance criteria - [ ] Typed options or a decoded type, decided per section 2 - [ ] Tests with argument lists ## Dependencies None known. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source CLI.md slice 1, not a duplicate. No dependencies. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source CLI.md slice 1, not a duplicate. No dependencies. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261023 until 2026-10-23T13:38Z

[loop:torbscript] claim refine by session:loop-torbscript-20261023 until 2026-10-23T13:38Z
Author
Collaborator

[loop:torbscript] decided by the loop: typed options in slice 1, decode<T> later. Why: CLI.md section 2 item 1 is a question of taste "decided with the first probe", i.e. an internal design choice (contract: loop decides, no owner question). option<Int>("jobs", default: 4) read back as input.option<Int>("jobs") needs only string-to-value conversion in a pure package; the Decode-based variant needs a Decoder over the argument map and Describe wiring into help, which is larger and best judged once slice 2 (torb itself, #124) shows real option structs. Shell completion (item 2) stays slice 3 (#125). Slice 1 therefore fits one PR; the decoded form becomes its own issue only if slice 2 wants it.

[loop:torbscript] refine: ready.

Goal. New package std/cli (pure except run, which only reads the argument list it is given): a program declares commands (nested), flags, options and positional arguments once, with a receiver-closure builder as in CLI.md section 1; help text and errors are generated from the declaration.

Design point. docs/design/CLI.md sections 1, 2 (item 1 decided above) and 3 (slice 1); ROADMAP std/cli row (#123).

Seed. Does not touch the seed: new std package, no syntax change, no new native, no driver flag, no std name the compiler looks up by string. (The compiler importing it is slice 2, #124, and needs the seed refresh there, Torben's.)

Acceptance criteria.

  • std/cli exists (project.trb, src/, tests/) and is importable as std/cli; building a tree with command "name" { description ...; command ...; flag ...; option<T>(...); arguments ...; run { input => ... } } as in CLI.md section 1 compiles.
  • flag("x") reads as input.flag("x") (--x, absent = false); option<T>("jobs", default: 4) reads as input.option<T>("jobs") for at least Int, Float64, Bool and String; both --jobs 8 and --jobs=8 work; a missing option without default and an unparsable value are errors.
  • Positional arguments: arguments("paths") collects the rest as a list; -- ends option parsing.
  • Subcommands dispatch by name; an unknown command or flag, a missing value, and a wrong type each produce an error that names the command and the argument, and exit non-zero from run.
  • Help for every command (--help, and help listing) is generated from the declaration: description, subcommands, flags, options with defaults, arguments.
  • Parsing is testable without a process: tests hand argument lists (List<String>) to the package and assert the parsed values, the help text and the exact error messages (happy path and each error case above).
  • A reference page docs/standard-library/cli.md (and skills/ regenerated if the docs gate asks), CLI.md status and section 2 item 1 updated to the decision.

Size. One PR, two Conventional Commits: feat(std/cli): commands, flags, options and arguments (package + tests) and docs(cli): std/cli reference and CLI.md decision. Gates: tier A in forge CI (the loop does not run bootstrap locally).

Out of scope. torb migration (#124), shell completion (#125), a Decode-based decode<T>(), environment-variable fallbacks.

Tokens used by this refine worker: not exposed to the worker (a small read-only pass: issue, CLI.md, ROADMAP rows, std layout).

next: implement

[loop:torbscript] decided by the loop: typed options in slice 1, `decode<T>` later. Why: CLI.md section 2 item 1 is a question of taste "decided with the first probe", i.e. an internal design choice (contract: loop decides, no owner question). `option<Int>("jobs", default: 4)` read back as `input.option<Int>("jobs")` needs only string-to-value conversion in a pure package; the `Decode`-based variant needs a `Decoder` over the argument map and `Describe` wiring into help, which is larger and best judged once slice 2 (`torb` itself, #124) shows real option structs. Shell completion (item 2) stays slice 3 (#125). Slice 1 therefore fits one PR; the decoded form becomes its own issue only if slice 2 wants it. [loop:torbscript] refine: ready. **Goal.** New package `std/cli` (pure except `run`, which only reads the argument list it is given): a program declares commands (nested), flags, options and positional arguments once, with a receiver-closure builder as in CLI.md section 1; help text and errors are generated from the declaration. **Design point.** docs/design/CLI.md sections 1, 2 (item 1 decided above) and 3 (slice 1); ROADMAP `std/cli` row (#123). **Seed.** Does not touch the seed: new std package, no syntax change, no new native, no driver flag, no std name the compiler looks up by string. (The compiler importing it is slice 2, #124, and needs the seed refresh there, Torben's.) **Acceptance criteria.** - [ ] `std/cli` exists (`project.trb`, `src/`, `tests/`) and is importable as `std/cli`; building a tree with `command "name" { description ...; command ...; flag ...; option<T>(...); arguments ...; run { input => ... } }` as in CLI.md section 1 compiles. - [ ] `flag("x")` reads as `input.flag("x")` (`--x`, absent = false); `option<T>("jobs", default: 4)` reads as `input.option<T>("jobs")` for at least `Int`, `Float64`, `Bool` and `String`; both `--jobs 8` and `--jobs=8` work; a missing option without default and an unparsable value are errors. - [ ] Positional arguments: `arguments("paths")` collects the rest as a list; `--` ends option parsing. - [ ] Subcommands dispatch by name; an unknown command or flag, a missing value, and a wrong type each produce an error that names the command and the argument, and exit non-zero from `run`. - [ ] Help for every command (`--help`, and `help` listing) is generated from the declaration: description, subcommands, flags, options with defaults, arguments. - [ ] Parsing is testable without a process: tests hand argument lists (`List<String>`) to the package and assert the parsed values, the help text and the exact error messages (happy path and each error case above). - [ ] A reference page `docs/standard-library/cli.md` (and `skills/` regenerated if the docs gate asks), CLI.md status and section 2 item 1 updated to the decision. **Size.** One PR, two Conventional Commits: `feat(std/cli): commands, flags, options and arguments` (package + tests) and `docs(cli): std/cli reference and CLI.md decision`. Gates: tier A in forge CI (the loop does not run bootstrap locally). **Out of scope.** `torb` migration (#124), shell completion (#125), a `Decode`-based `decode<T>()`, environment-variable fallbacks. Tokens used by this refine worker: not exposed to the worker (a small read-only pass: issue, CLI.md, ROADMAP rows, std layout). next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261023 until 2026-10-23T17:50Z

[loop:torbscript] claim implement by session:loop-torbscript-20261023 until 2026-10-23T17:50Z
argus closed this issue 2026-10-23 13:14:00 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#123
No description provided.