Build with Estii

How commands work

Command shape, references, paths, values, previews, output, and exit codes.

Enough to follow every workflow in this section. Every command's exact arguments and options are in its own --help.

Shape

A command is a noun, a verb, and what they act on:

estii <noun> <verb> [<ref>] [<path>] [<key>=<value>...] [flags]

The nouns that address your data are context, space, deal, pipeline, library, role, stream, product, tag, card, template, and run. Alongside them sit auth, init, self, cache, mcp, doctor, version, and commands. So estii deal add nd_abc123 tasks/tk_9/estimates resource="Senior Dev" amount=5d reads as: on the deal nd_abc123, under the estimates of task tk_9, add one with these two values.

estii context says what to build

Everything else here is how to phrase a command; that one is what a deal in your space is made of, what the space already holds to start from and reuse, which resource an estimate binds to and in what unit, and what a change is refused for. It answers in your space's own words, so if you have renamed a level it uses your name for it. Add a deal reference and it reports that deal's own shape and what may be changed on it now. Worth reading first, and worth handing to an assistant before it writes anything.

Paths address what lives inside a deal

Phases, categories, sections, line items, tasks, estimates, milestones, adjustments, comments, and versions exist only within a deal, so they are addressed as a path on it rather than as nouns of their own. A path names either a collection to create in or one node to act on. Omit the path and the command means the deal itself.

References may be an id or a name

estii deal show "ACME Customer Portal" works as well as the id. Names are matched loosely, ignoring case and punctuation. Ids are exact, so prefer them in a script; an ambiguous name exits non-zero and lists the candidates.

Ids come from deal find

A deal's own nodes each have an id, and estii deal find <ref> lists them with the exact path each write verb takes, alongside the units and price the app shows for each. It is how you get from "the discovery estimate" to estimates/es_4, and it ranks them at the same time. Anything you create also reports its own id, so a script that is building a deal never has to look one up.

Three reads, one question each

deal find says where something is, deal inspect says what one part of the deal is, and deal show says what the whole deal is worth. inspect takes an address inside the deal, show does not.

One space is active at a time

Set it once with estii space use acme, or override it per call with --space acme, or set ESTII_SPACE. With no space active and none passed, a command exits rather than picking one.

Values go in as pairs or as JSON

key=value suits a single field. --data '<json>' takes a whole body, and --data @file or --data - reads it from a file or standard input, which is what to use when a value carries quotes or line breaks. They set the same fields; passing both at once is an error.

Changes preview, then apply

At a terminal, a command that writes shows you the diff and asks before it applies. A script has no one to ask, so it passes --yes to apply or --dry-run to see the diff and stop; without either, it exits.

Output

Text by default, for reading. Add --json for one document or -o ndjson for a row per line. Those two are the stable contract.

Exit codes

Exit codes carry the outcome, so a script branches on the code rather than matching on message text: 0 success, 2 bad usage, 3 not authorised, 4 not found, 5 conflict or ambiguous, 6 temporarily unavailable and worth retrying, 7 client too old, 130 cancelled. Waiting on work that takes minutes adds two: 8 the work failed, 9 it is still going and you can wait again.

The line between 2 and 5 is where the refusal comes from. A command that cannot be understood — an unknown field, a value the field will not take — exits 2. A command that is understood but would leave your data in a state Estii does not mean exits 5: a rate card whose floor sits above its ceiling, a name two roles share, an estimate measured in a unit its resource does not count, a line pointing at something the same change removes. Every such refusal is checked before anything is sent, so nothing is half applied, and --json carries each one as its own entry with the field to change and the values that would satisfy it. State that was already there does not block you: it is reported and the change goes through.

Ask the binary

These pages cover the paths worth walking end to end. For the exact surface:

estii commands           # every command, with its arguments, options, and examples
estii commands deal      # just one noun's verbs
estii commands deal set  # one command's entry on its own
estii deal set --help    # one command in full

estii commands prints a table at a terminal and JSON when piped.