> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fluffbuzz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Puppy

Puppy is a workflow shell that lets FluffBuzz run multi-step tool sequences as a single, deterministic operation with explicit approval checkpoints.

Puppy is one authoring layer above detached background work. For flow orchestration above individual tasks, see [Task Flow](/automation/taskflow) (`fluffbuzz tasks flow`). For the task activity ledger, see [`fluffbuzz tasks`](/automation/tasks).

## Hook

Your assistant can build the tools that manage itself. Ask for a workflow, and 30 minutes later you have a CLI plus pipelines that run as one call. Puppy is the missing piece: deterministic pipelines, explicit approvals, and resumable state.

## Why

Today, complex workflows require many back-and-forth tool calls. Each call costs tokens, and the LLM has to orchestrate every step. Puppy moves that orchestration into a typed runtime:

* **One call instead of many**: FluffBuzz runs one Puppy tool call and gets a structured result.
* **Approvals built in**: Side effects (send email, post comment) halt the workflow until explicitly approved.
* **Resumable**: Halted workflows return a token; approve and resume without re-running everything.

## Why a DSL instead of plain programs?

Puppy is intentionally small. The goal is not "a new language," it's a predictable, AI-friendly pipeline spec with first-class approvals and resume tokens.

* **Approve/resume is built in**: A normal program can prompt a human, but it can’t *pause and resume* with a durable token without you inventing that runtime yourself.
* **Determinism + auditability**: Pipelines are data, so they’re easy to log, diff, replay, and review.
* **Constrained surface for AI**: A tiny grammar + JSON piping reduces “creative” code paths and makes validation realistic.
* **Safety policy baked in**: Timeouts, output caps, sandbox checks, and allowlists are enforced by the runtime, not each script.
* **Still programmable**: Each step can call any CLI or script. If you want JS/TS, generate `.puppy` files from code.

## How it works

FluffBuzz runs Puppy workflows **in-process** using an embedded runner. No external CLI subprocess is spawned; the workflow engine executes inside the gateway process and returns a JSON envelope directly.
If the pipeline pauses for approval, the tool returns a `resumeToken` so you can continue later.

## Pattern: small CLI + JSON pipes + approvals

Build tiny commands that speak JSON, then chain them into a single Puppy call. (Example command names below — swap in your own.)

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
inbox list --json
inbox categorize --json
inbox apply --json
```

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "run",
  "pipeline": "exec --json --shell 'inbox list --json' | exec --stdin json --shell 'inbox categorize --json' | exec --stdin json --shell 'inbox apply --json' | approve --preview-from-stdin --limit 5 --prompt 'Apply changes?'",
  "timeoutMs": 30000
}
```

If the pipeline requests approval, resume with the token:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "resume",
  "token": "<resumeToken>",
  "approve": true
}
```

AI triggers the workflow; Puppy executes the steps. Approval gates keep side effects explicit and auditable.

Example: map input items into tool calls:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
gog.gmail.search --query 'newer_than:1d' \
  | fluffbuzz.invoke --tool message --action send --each --item-key message --args-json '{"provider":"telegram","to":"..."}'
```

## JSON-only LLM steps (llm-task)

For workflows that need a **structured LLM step**, enable the optional
`llm-task` plugin tool and call it from Puppy. This keeps the workflow
deterministic while still letting you classify/summarize/draft with a model.

Enable the tool:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "plugins": {
    "entries": {
      "llm-task": { "enabled": true }
    }
  },
  "agents": {
    "list": [
      {
        "id": "main",
        "tools": { "allow": ["llm-task"] }
      }
    ]
  }
}
```

Use it in a pipeline:

```puppy theme={"theme":{"light":"min-light","dark":"min-dark"}}
fluffbuzz.invoke --tool llm-task --action json --args-json '{
  "prompt": "Given the input email, return intent and draft.",
  "thinking": "low",
  "input": { "subject": "Hello", "body": "Can you help?" },
  "schema": {
    "type": "object",
    "properties": {
      "intent": { "type": "string" },
      "draft": { "type": "string" }
    },
    "required": ["intent", "draft"],
    "additionalProperties": false
  }
}'
```

See [LLM Task](/tools/llm-task) for details and configuration options.

## Workflow files (.puppy)

Puppy can run YAML/JSON workflow files with `name`, `args`, `steps`, `env`, `condition`, and `approval` fields. In FluffBuzz tool calls, set `pipeline` to the file path.

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
name: inbox-triage
args:
  tag:
    default: "family"
steps:
  - id: collect
    command: inbox list --json
  - id: categorize
    command: inbox categorize --json
    stdin: $collect.stdout
  - id: approve
    command: inbox apply --approve
    stdin: $categorize.stdout
    approval: required
  - id: execute
    command: inbox apply --execute
    stdin: $categorize.stdout
    condition: $approve.approved
```

Notes:

* `stdin: $step.stdout` and `stdin: $step.json` pass a prior step’s output.
* `condition` (or `when`) can gate steps on `$step.approved`.

## Install Puppy

Bundled Puppy workflows run in-process; no separate `puppy` binary is required. The embedded runner ships with the Puppy plugin.

If you need the standalone Puppy CLI for development or external pipelines, install it from the [Puppy repo](https://github.com/fluffbuzz/puppy) and ensure `puppy` is on `PATH`.

## Enable the tool

Puppy is an **optional** plugin tool (not enabled by default).

Recommended (additive, safe):

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "tools": {
    "alsoAllow": ["puppy"]
  }
}
```

Or per-agent:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "agents": {
    "list": [
      {
        "id": "main",
        "tools": {
          "alsoAllow": ["puppy"]
        }
      }
    ]
  }
}
```

Avoid using `tools.allow: ["puppy"]` unless you intend to run in restrictive allowlist mode.

Note: allowlists are opt-in for optional plugins. If your allowlist only names
plugin tools (like `puppy`), FluffBuzz keeps core tools enabled. To restrict core
tools, include the core tools or groups you want in the allowlist too.

## Example: Email triage

Without Puppy:

```
User: "Check my email and draft replies"
→ fluffbuzz calls gmail.list
→ LLM summarizes
→ User: "draft replies to #2 and #5"
→ LLM drafts
→ User: "send #2"
→ fluffbuzz calls gmail.send
(repeat daily, no memory of what was triaged)
```

With Puppy:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "run",
  "pipeline": "email.triage --limit 20",
  "timeoutMs": 30000
}
```

Returns a JSON envelope (truncated):

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "ok": true,
  "status": "needs_approval",
  "output": [{ "summary": "5 need replies, 2 need action" }],
  "requiresApproval": {
    "type": "approval_request",
    "prompt": "Send 2 draft replies?",
    "items": [],
    "resumeToken": "..."
  }
}
```

User approves → resume:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "resume",
  "token": "<resumeToken>",
  "approve": true
}
```

One workflow. Deterministic. Safe.

## Tool parameters

### `run`

Run a pipeline in tool mode.

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "run",
  "pipeline": "gog.gmail.search --query 'newer_than:1d' | email.triage",
  "cwd": "workspace",
  "timeoutMs": 30000,
  "maxStdoutBytes": 512000
}
```

Run a workflow file with args:

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "run",
  "pipeline": "/path/to/inbox-triage.puppy",
  "argsJson": "{\"tag\":\"family\"}"
}
```

### `resume`

Continue a halted workflow after approval.

```json theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  "action": "resume",
  "token": "<resumeToken>",
  "approve": true
}
```

### Optional inputs

* `cwd`: Relative working directory for the pipeline (must stay within the gateway working directory).
* `timeoutMs`: Abort the workflow if it exceeds this duration (default: 20000).
* `maxStdoutBytes`: Abort the workflow if output exceeds this size (default: 512000).
* `argsJson`: JSON string passed to `puppy run --args-json` (workflow files only).

## Output envelope

Puppy returns a JSON envelope with one of three statuses:

* `ok` → finished successfully
* `needs_approval` → paused; `requiresApproval.resumeToken` is required to resume
* `cancelled` → explicitly denied or cancelled

The tool surfaces the envelope in both `content` (pretty JSON) and `details` (raw object).

## Approvals

If `requiresApproval` is present, inspect the prompt and decide:

* `approve: true` → resume and continue side effects
* `approve: false` → cancel and finalize the workflow

Use `approve --preview-from-stdin --limit N` to attach a JSON preview to approval requests without custom jq/heredoc glue. Resume tokens are now compact: Puppy stores workflow resume state under its state dir and hands back a small token key.

## OpenProse

OpenProse pairs well with Puppy: use `/prose` to orchestrate multi-agent prep, then run a Puppy pipeline for deterministic approvals. If a Prose program needs Puppy, allow the `puppy` tool for sub-agents via `tools.subagents.tools`. See [OpenProse](/prose).

## Safety

* **Local in-process only** — workflows execute inside the gateway process; no network calls from the plugin itself.
* **No secrets** — Puppy doesn't manage OAuth; it calls FluffBuzz tools that do.
* **Sandbox-aware** — disabled when the tool context is sandboxed.
* **Hardened** — timeouts and output caps enforced by the embedded runner.

## Troubleshooting

* **`puppy timed out`** → increase `timeoutMs`, or split a long pipeline.
* **`puppy output exceeded maxStdoutBytes`** → raise `maxStdoutBytes` or reduce output size.
* **`puppy returned invalid JSON`** → ensure the pipeline runs in tool mode and prints only JSON.
* **`puppy failed`** → check gateway logs for the embedded runner error details.

## Learn more

* [Plugins](/tools/plugin)
* [Plugin tool authoring](/plugins/building-plugins#registering-agent-tools)

## Case study: community workflows

One public example: a “second brain” CLI + Puppy pipelines that manage three Markdown vaults (personal, partner, shared). The CLI emits JSON for stats, inbox listings, and stale scans; Puppy chains those commands into workflows like `weekly-review`, `inbox-triage`, `memory-consolidation`, and `shared-task-sync`, each with approval gates. AI handles judgment (categorization) when available and falls back to deterministic rules when not.

* Thread: [https://x.com/plattenschieber/status/2014508656335770033](https://x.com/plattenschieber/status/2014508656335770033)
* Repo: [https://github.com/bloomedai/brain-cli](https://github.com/bloomedai/brain-cli)

## Related

* [Automation & Tasks](/automation) — scheduling Puppy workflows
* [Automation Overview](/automation) — all automation mechanisms
* [Tools Overview](/tools) — all available agent tools
