Output Modes
The JSON envelope, URL-only output, saving files locally, and --dry-run estimates.
Stdout and stderr
tufty keeps two kinds of output strictly apart:
- stdout holds exactly one JSON envelope (or, with
--format url, a list of URLs) — safe to hand to a parser; - stderr holds progress, the credit estimate, saved file paths and hints. While waiting in an interactive terminal it also prints dots; agents and pipes get none.
Success
{
"ok": true,
"result": {
"tool": "pet-dressup",
"runId": "3f6c2a1e-8b4d-4e7a-9c55-0d2b7e1f4a90",
"status": "completed",
"outputs": [
{ "type": "image", "url": "https://static.tufty.ai/.../result.png" }
]
}
}| Field | Description |
|---|---|
tool | Tool id |
runId | Run id, usable with tufty status |
status | completed; running with --no-wait |
outputs[].type | image or video |
outputs[].url | Output URL, hosted on static.tufty.ai |
outputs[].path | With --save, the absolute path of the local file |
result for other commands:
| Command | result |
|---|---|
tufty tools list | { tool: "tools.list", data: { locale, tools: [{ id, kind, name, description, command }] } } |
tufty tools describe <id> | { tool: "tools.describe", data: the tool's manifest entry } |
tufty upload <file> | { tool: "upload", data: { url } } |
tufty auth set <apiKey> | { tool: "auth.set", data: { source: "config", saved: true } } |
tufty auth get | { tool: "auth.get", data: { source, apiKey } } |
tufty login | { tool: "login", data: { saved: true } } |
tufty logout | { tool: "logout", data: { removed } } |
Failure
{
"ok": false,
"code": "insufficient_balance",
"message": "Not enough credits (this step needs 75).",
"details": { "status": 402, "required": 75 }
}message is fit to show a person; branch on code in code. Every code is listed in Error codes; see also Exit codes.
--format url
tufty pet-dressup --product ./sweater.jpg --model ./corgi.jpg --format urlStdout lists one output URL per line:
https://static.tufty.ai/.../result.pngIt only applies when the result actually has URLs. Results without any — tufty tools list, --no-wait — still print the full envelope, and so do failures. tufty upload and tufty status accept --format url too.
--save <dir>
tufty image-to-video --still ./corgi-sweater.png --duration 5 --save ./outWhen the run finishes, the CLI downloads each output into the directory (creating it if needed) as <runId>-<n><extension>. Each download is written to a .partial file and renamed when complete, with up to 3 attempts; the absolute path is added as outputs[].path.
--save only works while waiting for the result; combined with --no-wait nothing is downloaded.
--dry-run
tufty pet-dressup --product ./sweater.jpg --model ./corgi.jpg ./shiba.jpg --quality medium --count 2 --dry-runValidates the inputs and prints the request payload and credit estimate — nothing is uploaded or charged, and no sign-in is needed.
{
"ok": true,
"result": {
"tool": "pet-dressup",
"dryRun": true,
"payload": {
"tool": "pet-dressup",
"products": ["./sweater.jpg"],
"models": ["./corgi.jpg", "./shiba.jpg"],
"count": 2,
"quality": "medium"
},
"estimatedCredits": 75,
"creditBreakdown": { "generation": 72, "cutout": 3 }
}
}The payload holds local paths rather than uploaded URLs — the CLI uploads only on a real run. How the estimate is computed: Credits.
