From c8d9d63408e0233a93d655f26b42cf26c2eecb3c Mon Sep 17 00:00:00 2001 From: temp-deepshard <304551954+temp-deepshard@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:51:49 -0700 Subject: [PATCH 1/5] Simplify Truffile agent setup guidance --- README.md | 69 +++++++++++++----- tests/test_agent_guidance.py | 38 ++++++++++ truffile/skills/truffile-chat/SKILL.md | 39 ++++++++--- truffile/skills/truffile-cli/SKILL.md | 73 +++++++++++++------- truffile/skills/truffile-infer/SKILL.md | 9 ++- truffile/skills/truffle-app-creator/SKILL.md | 27 +++++--- 6 files changed, 191 insertions(+), 64 deletions(-) create mode 100644 tests/test_agent_guidance.py diff --git a/README.md b/README.md index 728369d..7a6d63d 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,38 @@ Python SDK/CLI for Truffle devices. +## Agent setup + +Give this to Codex, Claude Code, or another coding agent from the workspace +where you want to use Truffile. Replace the final placeholder with the result +you actually want: + +> Set up the latest Truffile in this workspace, then ****. Follow the +> [installation guide](https://docs.truffle.net/sdk/installation). Use Python +> 3.12 or newer, prefer `uv` when available, and create a local `.venv`. Run +> `truffile load all --json`, read the copied skills, then run +> `truffile doctor --json` and use non-interactive JSON commands. Do not stop +> after setup; continue to my goal. Ask me only when you need Symphony +> onboarding, my User ID from Symphony Settings, approval on the physical +> Truffle, credentials, or confirmation of a deployment or destructive action. + +How the pieces fit: + +- Symphony onboards the Truffle and supplies the User ID used for pairing. +- Truffile gives a coding agent a local CLI and SDK for the device. +- `truffile chat` talks to the on-device agent, including its tasks and apps. +- `truffile infer` calls the raw on-device model and can test MCP servers. +- The user still approves pairing on the device and authorizes deployments or + destructive actions. + ## What It Does - discovers and connects to your Truffle (`scan`, `connect`, `disconnect`) - copies bundled agent resources into your workspace (`load`) +- diagnoses the local-to-device path (`doctor`) - validates and deploys apps from `truffile.yaml` (`validate`, `deploy`) - manages installed apps (`list apps`, `delete`) -- talks to inference directly (`models`, `chat`) +- talks to the on-device agent (`chat`) or raw inference service (`infer`) ## Start making your Own Apps @@ -49,19 +74,29 @@ In practice: ## Core Commands ```bash -truffile scan -truffile connect -truffile create [app_name] -truffile load all -truffile validate [app_dir] -truffile deploy [app_dir] -truffile deploy --dry-run [app_dir] +truffile --version +truffile load all --json +truffile doctor --json +truffile scan --json --non-interactive +truffile connect --user-id --json --non-interactive +truffile create --path ./apps --json --non-interactive +truffile validate ./apps/ --json +truffile deploy ./apps/ --dry-run --json --non-interactive +truffile deploy ./apps/ --json --non-interactive truffile list apps --json -truffile delete -truffile models -truffile chat +truffile delete --dry-run --json --non-interactive +truffile delete --yes --json --non-interactive +truffile models --json +truffile chat --quiet --json "your request" +truffile infer --quiet --json "your prompt" ``` +For a first connection, onboard the device in +[Symphony](https://docs.truffle.net/client/overview), copy the User ID from +Symphony Settings, run the `scan` and `connect` commands above, then approve +the new session on the Truffle. Installation and local validation do not +require a connected device. + `truffile create` scaffolds a hybrid app starter with: - `truffile.yaml` (foreground + background process config) - copy-file steps for generated `*_foreground.py` and `*_background.py` @@ -130,12 +165,12 @@ Refresh vendored protos from firmware repo: The supported app development loop is CLI-first: ```bash -truffile create my-app --path ./apps -truffile validate ./apps/my-app -truffile deploy --dry-run ./apps/my-app -truffile deploy ./apps/my-app +truffile create my-app --path ./apps --json --non-interactive +truffile validate ./apps/my-app --json +truffile deploy ./apps/my-app --dry-run --json --non-interactive +truffile deploy ./apps/my-app --json --non-interactive ``` After deploy, use `truffile chat` to attach the app to a task and exercise its -tools with the on-device agent. Use `truffile delete` to remove test apps from -the connected device. +tools with the on-device agent. Preview removal with `truffile delete +--dry-run --json --non-interactive`; only add `--yes` after the user confirms. diff --git a/tests/test_agent_guidance.py b/tests/test_agent_guidance.py new file mode 100644 index 0000000..e772cab --- /dev/null +++ b/tests/test_agent_guidance.py @@ -0,0 +1,38 @@ +from pathlib import Path + + +ROOT = Path(__file__).parents[1] +README = (ROOT / "README.md").read_text() +CLI_SKILL = (ROOT / "truffile/skills/truffile-cli/SKILL.md").read_text() +CHAT_SKILL = (ROOT / "truffile/skills/truffile-chat/SKILL.md").read_text() +APP_SKILL = (ROOT / "truffile/skills/truffle-app-creator/SKILL.md").read_text() + + +def test_setup_prompt_is_goal_first_and_names_human_boundaries(): + single_line = README.replace("\n> ", " ").replace("\n", " ") + assert "then ****" in single_line + assert "Do not stop after setup" in single_line + assert "User ID from Symphony Settings" in single_line + assert "approval on the physical" in single_line + + +def test_cli_skill_prefers_machine_contract_and_safe_deletion(): + assert "truffile doctor --json" in CLI_SKILL + assert "truffile scan --json --non-interactive" in CLI_SKILL + assert '--user-id "$TRUFFLE_USER_ID"' in CLI_SKILL + assert "delete my-app --dry-run --json --non-interactive" in CLI_SKILL + assert "delete my-app --yes --json --non-interactive" in CLI_SKILL + assert "Settings >\nAbout" not in CLI_SKILL + + +def test_chat_skill_documents_bounded_compact_output(): + assert "--max-output-bytes" in CHAT_SKILL + assert "--include-thinking" in CHAT_SKILL + assert "--include-tools" in CHAT_SKILL + assert "interrupt a known task" in CHAT_SKILL + assert "Reserved:" not in CHAT_SKILL + + +def test_app_creator_keeps_working_before_device_pairing(): + assert "finish the\nlocal app, tests, validation, and dry-run" in APP_SKILL + assert "truffile create my-app --path ./apps --json --non-interactive" in APP_SKILL diff --git a/truffile/skills/truffile-chat/SKILL.md b/truffile/skills/truffile-chat/SKILL.md index 7c30b5c..14ea849 100644 --- a/truffile/skills/truffile-chat/SKILL.md +++ b/truffile/skills/truffile-chat/SKILL.md @@ -55,24 +55,33 @@ In one-shot mode: error diagnostics, and (with `--show-thinking`) the agent's thinking summaries. Pass `--quiet` to silence stderr entirely. - Exit code is `0` on success, `1` on error, `130` on Ctrl+C. +- JSON is compact by default. Thinking summaries and tool names are omitted + unless requested, and response content is bounded by `--max-output-bytes`. `--json` payload shape: ```json { + "schema_version": "1", + "status": "ok", "task_id": "uuid-of-the-task", "title": "Generated task title", "device": "truffle-1234", "content": "the agent's final response text", - "thinking": ["summary 1", "summary 2"] | null, - "tool_calls": ["tool_a", "tool_b"] | null, + "content_bytes": 39, + "returned_bytes": 39, + "truncated": false, + "task_status": "ready", + "run_state": "TASK_RUN_STATE_READY", "pending_user_response": false, - "attached_apps": ["Slack", "Gmail"] | null + "attached_apps": ["Slack", "Gmail"] } ``` `pending_user_response: true` means the agent is waiting for a follow-up message — call `truffile chat --task-id "answer"` to continue. +Add `--include-thinking`, `--include-tools`, or `--full` only when that detail +is needed. ## Full flag reference @@ -106,8 +115,12 @@ message — call `truffile chat --task-id "answer"` to continue. |---|---| | `--json` | Emit a structured JSON object on stdout | | `--show-thinking` | Include the agent's thinking summaries on stderr | +| `--include-thinking` | Include thinking summaries in JSON | +| `--include-tools` | Include tool names in JSON | +| `--full` | Include both thinking summaries and tool names in JSON | +| `--max-output-bytes N` | Bound returned UTF-8 content bytes (default 65536) | | `--quiet`, `-q` | Suppress all stderr decoration | -| `--timeout SECONDS` | Reserved: max seconds to wait for the task to settle | +| `--timeout SECONDS` | Stop waiting and interrupt a known task after this limit | ## Cookbook @@ -163,7 +176,8 @@ truffile chat --list-tasks 10 --quiet As JSON: ```bash -truffile chat --list-tasks 5 --json --quiet | jq '.tasks[] | .title' +truffile chat --list-tasks 5 --json --quiet \ + | jq '.tasks[] | {task_id, title, status, pending_user_response}' ``` ### Resume the most recent task and add a follow-up @@ -182,6 +196,11 @@ truffile chat --quiet --task-id 0c83cc07-4ee5-410f-8c0a-be8152644f24 \ truffile chat --quiet --json --task-id | jq .content ``` +Use `--full` only for explicit debugging: +```bash +truffile chat --quiet --json --full --task-id +``` + ### Show what the agent was thinking on stderr ```bash truffile chat --show-thinking "explain why my last deploy failed" @@ -246,11 +265,11 @@ truffile chat --quiet --app "$APP_NAME" "..." all work the same way they do on a LAN client. See the `truffile-cli` skill's "Running inside a Truffle app container" section for the full contract. -- **No device connected (LAN) → first-run onboarding fires.** The CLI will - ask for a truffle number and user id, then run `truffile connect` - automatically. This still requires the user to **physically tap "approve" - on the Truffle device screen**. After that, all subsequent commands work - without re-prompting. +- **No device connected in machine mode → structured failure.** Run + `truffile doctor --json`, then onboard in Symphony and connect with the + non-interactive command in the `truffile-cli` skill. Interactive mode can + still walk a human through the same flow. Pairing requires the user to + physically approve the session on the Truffle. - **App matching is fuzzy.** `slack` matches `Slack`. If two app names overlap, the first match wins — use the uuid for absolute precision. - **`--task-id` without a prompt does NOT send a message.** It just opens the diff --git a/truffile/skills/truffile-cli/SKILL.md b/truffile/skills/truffile-cli/SKILL.md index 37fd505..756dd1b 100644 --- a/truffile/skills/truffile-cli/SKILL.md +++ b/truffile/skills/truffile-cli/SKILL.md @@ -11,6 +11,19 @@ description: | Use this for Truffle device and app lifecycle work. +## Agent workflow + +1. Preserve the user's original goal; setup is a prerequisite, not the result. +2. Run `truffile --version`, `truffile load all --json`, and + `truffile doctor --json` before guessing about state. +3. Prefer `--json --non-interactive` for commands that support them. Treat + stdout as machine output and report the command's `code`, `message`, and + `next_action` when it fails. +4. Continue through local create and validation even when no device is paired. +5. Pause only for a human boundary: Symphony onboarding, User ID, physical + device approval, credentials, deployment approval, or destructive action + confirmation. + ## Connection Assumptions When running inside a Truffle app or agent container, assume the runtime has @@ -22,29 +35,37 @@ Symphony desktop client: https://docs.truffle.net/client/overview -After onboarding, ask the user for the User ID from Symphony **Settings > -About** if they have not already provided it. `truffile connect` uses that User -ID and then the user must approve the new session on the Truffle device. -Stored credentials are reused after the first approval. +After onboarding, ask the user for the User ID from Symphony **Settings** if +they have not already provided it. `truffile connect` uses that User ID and +then the user must approve the new session on the Truffle device. Stored +credentials are reused after the first approval. Useful checks: ```bash -truffile connect truffle-1234 -truffile list devices -truffile list apps +truffile doctor --json +truffile scan --json --non-interactive +truffile connect truffle-1234 --user-id "$TRUFFLE_USER_ID" \ + --json --non-interactive --approval-timeout 120 +truffile list devices --json +truffile list apps --json ``` +`connect` can return discovery, authentication, or approval failures as +structured JSON. Pairing always requires the user to approve the new session +on the physical Truffle. Do not ask them to paste a session token. + ## Core Commands ### Discover and Connect ```bash -truffile scan -truffile connect truffle-1234 --user-id "$TRUFFLE_USER_ID" -truffile list devices -truffile disconnect truffle-1234 -truffile disconnect all +truffile scan --json --non-interactive +truffile connect truffle-1234 --user-id "$TRUFFLE_USER_ID" \ + --json --non-interactive --approval-timeout 120 +truffile list devices --json +truffile disconnect truffle-1234 --json +truffile disconnect all --json ``` Inside a container, `connect` is effectively a no-op success because the @@ -53,9 +74,9 @@ session comes from env. ### Create and Validate an App ```bash -truffile load all -truffile create my-app --path ./apps -truffile validate ./apps/my-app +truffile load all --json +truffile create my-app --path ./apps --json --non-interactive +truffile validate ./apps/my-app --json ``` `truffile load all` copies bundled skills and example apps into @@ -68,27 +89,27 @@ Run validation before deploy. Validation is local and does not need a device. ### Deploy a Local App Directory ```bash -truffile deploy ./apps/my-app -truffile deploy ./apps/my-app --dry-run +truffile deploy ./apps/my-app --dry-run --json --non-interactive +truffile deploy ./apps/my-app --json --non-interactive truffile deploy ./apps/my-app --json --non-interactive --replace truffile deploy ./apps/my-app --interactive ``` -Use `--dry-run` before a risky deploy. Use `--interactive` only for debugging -inside the build container before finalizing. +Run `--dry-run` first. Deploy only when the user asked for deployment, and use +`--replace` only when they approved replacing the installed bundle. Use +`--interactive` only for debugging inside the build container. ### Delete Installed Apps ```bash truffile list apps --json -truffile delete my-app -truffile delete 1 -truffile delete 1 2 3 -truffile delete all +truffile delete my-app --dry-run --json --non-interactive +truffile delete my-app --yes --json --non-interactive ``` Prefer deleting by app name, slug, or uuid. Numeric indices still work, but -they are less safe for agent workflows because app ordering can change. +they are less safe for agent workflows because app ordering can change. Never +add `--yes` until the user has confirmed the exact apps shown by `--dry-run`. ### Obsidian @@ -124,6 +145,8 @@ ToolSpec( ## Output Habits -- Use `--json` when available for scripting. +- Use `--json` when available for scripting. Successful payloads contain + `schema_version` and `status: "ok"`; failures contain `status: "error"` plus + stable `code`, `message`, `retryable`, and `next_action` fields. - Keep stdout clean when feeding another command. - Relay important command results to the user; they do not see shell output. diff --git a/truffile/skills/truffile-infer/SKILL.md b/truffile/skills/truffile-infer/SKILL.md index c8a686c..4f8afb6 100644 --- a/truffile/skills/truffile-infer/SKILL.md +++ b/truffile/skills/truffile-infer/SKILL.md @@ -56,6 +56,11 @@ In one-shot mode: This means you can always do `truffile infer --quiet "..."` and get a clean, parseable response on stdout with no preamble. +Before inference, use `truffile doctor --json` to distinguish connection, +authentication, and IF2 service failures. In `--json` mode, failures keep a +stable `code`, `message`, `retryable`, and `next_action`, including HTTP 503 +service-unavailable responses. + ## Full flag reference ### Conversation @@ -248,8 +253,8 @@ truffile infer --quiet --prompt-file ./prompt.txt --max-tokens 1024 `--mcp`, image attachments, and `--json` all work the same way they do on a LAN client. See the `truffile-cli` skill's "Running inside a Truffle app container" section for the full contract. -- **No device connected (LAN) → exit 1.** Run `truffile list devices` to - verify a Truffle is connected before invoking infer in scripts. +- **No device connected (LAN) → exit 1.** Run `truffile doctor --json` to + identify whether discovery, pairing, authentication, or IF2 is missing. - **`--mcp` URLs must start with `http://` or `https://`.** Streamable HTTP only. - **`--tool-args` must be a JSON object** (not an array, not a bare value). - **Default behavior is non-streaming in one-shot mode.** Pass `--stream` if diff --git a/truffile/skills/truffle-app-creator/SKILL.md b/truffile/skills/truffle-app-creator/SKILL.md index 46eda9e..7783cb5 100644 --- a/truffile/skills/truffle-app-creator/SKILL.md +++ b/truffile/skills/truffle-app-creator/SKILL.md @@ -62,6 +62,10 @@ Reference: see references/auth-patterns.md for the decision tree. ### Step 4: Scaffold the app Create the directory structure, the command truffile create does this, read the docs first: +```bash +truffile create my-app --path ./apps --json --non-interactive +``` + ``` my-app/ ├── truffile.yaml @@ -128,8 +132,8 @@ Subclass BackgroundWorkerApp with the 4 required methods. Follow the rules: Don't wait until the end. Write tests as you implement: ```bash -truffile validate ./my-app # yaml + source checks -python -m pytest ./my-app/tests/ -v # unit tests +truffile validate ./apps/my-app --json # yaml + source checks +python -m pytest ./apps/my-app/tests/ -v # unit tests ``` Use FakeHttpTransport and AppHarness. See references/testing-guide.md. @@ -137,9 +141,9 @@ Use FakeHttpTransport and AppHarness. See references/testing-guide.md. ### Step 9: Validate and iterate Run validation: -- `truffile validate ./my-app` — check manifest, file references, and Python syntax -- `truffile deploy --dry-run ./my-app` — inspect the deploy plan without changing the device -- `python -m pytest ./my-app/tests/` — run tests +- `truffile validate ./apps/my-app --json` — check manifest, file references, and Python syntax +- `truffile deploy ./apps/my-app --dry-run --json --non-interactive` — inspect the deploy plan without changing the device +- `python -m pytest ./apps/my-app/tests/` — run tests Fix any issues. Repeat until everything passes. @@ -147,13 +151,16 @@ Fix any issues. Repeat until everything passes. If the user has a device connected: ```bash -truffile deploy ./my-app +truffile deploy ./apps/my-app --json --non-interactive ``` +Deploy only when the user requested it. If no device is connected, finish the +local app, tests, validation, and dry-run; then give the exact connection +blocker instead of abandoning the build. + Then test with the agent: ```bash -truffile chat -you> [test the app's tools] +truffile chat --quiet --json --app my-app "test the app's tools" ``` ### Step 11: Create skills (optional) @@ -174,8 +181,8 @@ Common issues during app creation: | Script | What it does | |--------|-------------| | `scripts/fetch_docs.py` | pull docs from docs.truffle.net | -| `truffile validate ` | check truffile.yaml, referenced files, and Python syntax | -| `truffile deploy --dry-run ` | inspect the deploy plan without changing the device | +| `truffile validate --json` | check truffile.yaml, referenced files, and Python syntax | +| `truffile deploy --dry-run --json --non-interactive` | inspect the deploy plan without changing the device | ## Reference docs From 3ecca20ef77731a29a6d3855379a85b20c9d4e76 Mon Sep 17 00:00:00 2001 From: temp-deepshard <304551954+temp-deepshard@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:51:49 -0700 Subject: [PATCH 2/5] Align Truffile agent guidance --- README.md | 4 ++-- tests/test_agent_guidance.py | 4 +++- truffile/skills/truffile-chat/SKILL.md | 4 ++-- truffile/skills/truffile-cli/SKILL.md | 5 +++-- truffile/skills/truffile-infer/SKILL.md | 5 +++-- truffile/skills/truffle-app-creator/SKILL.md | 17 +++++++++++------ 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7a6d63d..50b39bf 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ Python SDK/CLI for Truffle devices. Give this to Codex, Claude Code, or another coding agent from the workspace where you want to use Truffile. Replace the final placeholder with the result -you actually want: +you actually want and how the agent can tell it is done: -> Set up the latest Truffile in this workspace, then ****. Follow the +> Set up the latest Truffile in this workspace, then ****. Follow the > [installation guide](https://docs.truffle.net/sdk/installation). Use Python > 3.12 or newer, prefer `uv` when available, and create a local `.venv`. Run > `truffile load all --json`, read the copied skills, then run diff --git a/tests/test_agent_guidance.py b/tests/test_agent_guidance.py index e772cab..fba4c4e 100644 --- a/tests/test_agent_guidance.py +++ b/tests/test_agent_guidance.py @@ -10,7 +10,7 @@ def test_setup_prompt_is_goal_first_and_names_human_boundaries(): single_line = README.replace("\n> ", " ").replace("\n", " ") - assert "then ****" in single_line + assert "then ****" in single_line assert "Do not stop after setup" in single_line assert "User ID from Symphony Settings" in single_line assert "approval on the physical" in single_line @@ -36,3 +36,5 @@ def test_chat_skill_documents_bounded_compact_output(): def test_app_creator_keeps_working_before_device_pairing(): assert "finish the\nlocal app, tests, validation, and dry-run" in APP_SKILL assert "truffile create my-app --path ./apps --json --non-interactive" in APP_SKILL + assert "Ask the user which approach they prefer" not in APP_SKILL + assert "Ask the user if they want to add skills" not in APP_SKILL diff --git a/truffile/skills/truffile-chat/SKILL.md b/truffile/skills/truffile-chat/SKILL.md index 14ea849..8d47b2b 100644 --- a/truffile/skills/truffile-chat/SKILL.md +++ b/truffile/skills/truffile-chat/SKILL.md @@ -283,5 +283,5 @@ truffile chat --quiet --app "$APP_NAME" "..." `--task-id` or `--resume-last` always starts a fresh task — old conversation context is not carried over. - **Tool calls are surfaced on stderr** in plain mode. In `--json` mode they - appear in the `tool_calls` array. With `--quiet`, you only see them via the - JSON payload. + are omitted by default; add `--include-tools` or `--full` when you need the + `tool_calls` array. diff --git a/truffile/skills/truffile-cli/SKILL.md b/truffile/skills/truffile-cli/SKILL.md index 756dd1b..78b8423 100644 --- a/truffile/skills/truffile-cli/SKILL.md +++ b/truffile/skills/truffile-cli/SKILL.md @@ -18,7 +18,7 @@ Use this for Truffle device and app lifecycle work. `truffile doctor --json` before guessing about state. 3. Prefer `--json --non-interactive` for commands that support them. Treat stdout as machine output and report the command's `code`, `message`, and - `next_action` when it fails. + any `next_action` when it fails. 4. Continue through local create and validation even when no device is paired. 5. Pause only for a human boundary: Symphony onboarding, User ID, physical device approval, credentials, deployment approval, or destructive action @@ -147,6 +147,7 @@ ToolSpec( - Use `--json` when available for scripting. Successful payloads contain `schema_version` and `status: "ok"`; failures contain `status: "error"` plus - stable `code`, `message`, `retryable`, and `next_action` fields. + stable `code`, `message`, and `retryable` fields. They include `next_action` + when a concrete recovery command or human action is known. - Keep stdout clean when feeding another command. - Relay important command results to the user; they do not see shell output. diff --git a/truffile/skills/truffile-infer/SKILL.md b/truffile/skills/truffile-infer/SKILL.md index 4f8afb6..07e9407 100644 --- a/truffile/skills/truffile-infer/SKILL.md +++ b/truffile/skills/truffile-infer/SKILL.md @@ -58,8 +58,9 @@ parseable response on stdout with no preamble. Before inference, use `truffile doctor --json` to distinguish connection, authentication, and IF2 service failures. In `--json` mode, failures keep a -stable `code`, `message`, `retryable`, and `next_action`, including HTTP 503 -service-unavailable responses. +stable `code`, `message`, and `retryable`; they include `next_action` when a +concrete recovery step is known. HTTP 503 responses remain visible as +service-unavailable errors. ## Full flag reference diff --git a/truffile/skills/truffle-app-creator/SKILL.md b/truffile/skills/truffle-app-creator/SKILL.md index 7783cb5..0920b1c 100644 --- a/truffile/skills/truffle-app-creator/SKILL.md +++ b/truffile/skills/truffle-app-creator/SKILL.md @@ -23,7 +23,8 @@ Activate when the user wants to: ### Step 1: Understand what the user wants -Interview the user: +Start from the user's stated goal and infer safe defaults. Ask only for missing +answers that would materially change behavior, auth, data access, or scope: - what service or API do they want to connect? - what should the agent be able to DO with it? (foreground tools) - what should happen automatically in the background? (background monitoring) @@ -31,7 +32,7 @@ Interview the user: Explain the difference between foreground and background clearly: - foreground: tools the agent calls during a conversation (search, send, check) -- background: scheduled jobs that submit context to the background agent running on their Truffle that decides whether submiited context is worth posting or taking an action on or not +- background: scheduled jobs that submit context to the background agent running on their Truffle, which decides whether submitted context is worth posting or acting on - they run in separate containers and cannot talk to each other directly - use app variables to share state between them @@ -42,12 +43,14 @@ Before building from scratch, search for: - open source libraries or SDKs for the API - existing Truffle apps that do something similar -Use web search to find options. Present them to the user with pros/cons: +Use web search to find options and compare: - if an MCP server exists: can we proxy it or wrap it? - if an SDK exists: can we build tools on top of it? - if nothing exists: we build from scratch using the API docs -Ask the user which approach they prefer. +Choose the smallest well-supported approach when the tradeoff is reversible. +Ask the user only when the alternatives materially change product behavior, +credentials, data exposure, or implementation scope. ### Step 3: Decide the app architecture @@ -163,9 +166,11 @@ Then test with the agent: truffile chat --quiet --json --app my-app "test the app's tools" ``` -### Step 11: Create skills (optional) +### Step 11: Create skills when useful -Ask the user if they want to add skills — workflow guides that teach the agent how to use the app's tools effectively. Create SKILL.md files under skills/foreground/ and skills/background/. +Add workflow skills under `skills/foreground/` or `skills/background/` when +the app needs repeatable usage guidance. Otherwise mention them as an optional +follow-up in the handoff instead of stopping implementation to ask. ## Error handling From 4fae6f3f1a815574d6de71a890f2092d7f3e468a Mon Sep 17 00:00:00 2001 From: temp-deepshard <304551954+temp-deepshard@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:16:25 -0700 Subject: [PATCH 3/5] Simplify and align agent guidance --- README.md | 20 +++++++++----------- tests/test_agent_guidance.py | 18 ++++++++++++------ truffile/skills/truffile-chat/SKILL.md | 12 ++++++++---- truffile/skills/truffile-cli/SKILL.md | 4 ++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 50b39bf..f1a73dc 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,15 @@ Python SDK/CLI for Truffle devices. ## Agent setup Give this to Codex, Claude Code, or another coding agent from the workspace -where you want to use Truffile. Replace the final placeholder with the result -you actually want and how the agent can tell it is done: - -> Set up the latest Truffile in this workspace, then ****. Follow the -> [installation guide](https://docs.truffle.net/sdk/installation). Use Python -> 3.12 or newer, prefer `uv` when available, and create a local `.venv`. Run -> `truffile load all --json`, read the copied skills, then run -> `truffile doctor --json` and use non-interactive JSON commands. Do not stop -> after setup; continue to my goal. Ask me only when you need Symphony -> onboarding, my User ID from Symphony Settings, approval on the physical -> Truffle, credentials, or confirmation of a deployment or destructive action. +where you want to use Truffile. Replace the placeholder with what you want to +do with your Truffle: + +> Set up the latest Truffile in this workspace, then ****. Follow the +> [installation guide](https://docs.truffle.net/sdk/installation). Run +> `truffile load all --json` and `truffile doctor --json`, then follow the +> copied skills. Continue through all work that does not need me. Ask only for +> Symphony onboarding or my User ID, approval on the physical Truffle, +> credentials, or confirmation before deployment or a destructive action. How the pieces fit: diff --git a/tests/test_agent_guidance.py b/tests/test_agent_guidance.py index fba4c4e..5c7d783 100644 --- a/tests/test_agent_guidance.py +++ b/tests/test_agent_guidance.py @@ -8,12 +8,16 @@ APP_SKILL = (ROOT / "truffile/skills/truffle-app-creator/SKILL.md").read_text() +def compact(text: str) -> str: + return " ".join(text.split()) + + def test_setup_prompt_is_goal_first_and_names_human_boundaries(): - single_line = README.replace("\n> ", " ").replace("\n", " ") - assert "then ****" in single_line - assert "Do not stop after setup" in single_line - assert "User ID from Symphony Settings" in single_line - assert "approval on the physical" in single_line + prompt = compact(README) + assert "then ****" in prompt + assert "Continue through all work that does not need me" in prompt + assert "Symphony onboarding or my User ID" in prompt + assert "approval on the physical" in prompt def test_cli_skill_prefers_machine_contract_and_safe_deletion(): @@ -30,11 +34,13 @@ def test_chat_skill_documents_bounded_compact_output(): assert "--include-thinking" in CHAT_SKILL assert "--include-tools" in CHAT_SKILL assert "interrupt a known task" in CHAT_SKILL + assert "task_not_waiting" in CHAT_SKILL + assert "pending_user_response" in CHAT_SKILL assert "Reserved:" not in CHAT_SKILL def test_app_creator_keeps_working_before_device_pairing(): - assert "finish the\nlocal app, tests, validation, and dry-run" in APP_SKILL + assert "finish the local app, tests, validation, and dry-run" in compact(APP_SKILL) assert "truffile create my-app --path ./apps --json --non-interactive" in APP_SKILL assert "Ask the user which approach they prefer" not in APP_SKILL assert "Ask the user if they want to add skills" not in APP_SKILL diff --git a/truffile/skills/truffile-chat/SKILL.md b/truffile/skills/truffile-chat/SKILL.md index 8d47b2b..50fdc48 100644 --- a/truffile/skills/truffile-chat/SKILL.md +++ b/truffile/skills/truffile-chat/SKILL.md @@ -80,6 +80,8 @@ In one-shot mode: `pending_user_response: true` means the agent is waiting for a follow-up message — call `truffile chat --task-id "answer"` to continue. +If the task is no longer waiting, the same command returns `task_not_waiting`; +omit `--task-id` to start a new task. Add `--include-thinking`, `--include-tools`, or `--full` only when that detail is needed. @@ -95,8 +97,8 @@ is needed. ### Task targeting | Flag | What it does | |---|---| -| `--task-id ID` | Resume a specific task. With a prompt: send follow-up. Without: peek state | -| `--resume-last` | Resume the most recent task on the device | +| `--task-id ID` | Read a task, or answer it with a prompt only while it is waiting | +| `--resume-last` | Target the most recent task; prompted follow-up still requires it to be waiting | | `--resume` | (REPL only) Open the interactive task picker | ### App attachment @@ -181,6 +183,7 @@ truffile chat --list-tasks 5 --json --quiet \ ``` ### Resume the most recent task and add a follow-up +Use this only when the task is waiting for a user response: ```bash truffile chat --quiet --resume-last "tell me more about the second item" ``` @@ -273,8 +276,9 @@ truffile chat --quiet --app "$APP_NAME" "..." - **App matching is fuzzy.** `slack` matches `Slack`. If two app names overlap, the first match wins — use the uuid for absolute precision. - **`--task-id` without a prompt does NOT send a message.** It just opens the - task and dumps current state. Combine with `--json` to inspect, or with a - prompt to send a follow-up. + task and dumps current state. A prompt answers the task only while + `pending_user_response` is true. Completed tasks return `task_not_waiting`; + omit `--task-id` to start a new task. - **`--resume-last` picks the most recently updated task,** which is usually the one the user was just looking at — but not always. - **`--quiet` suppresses error explanations on stderr too.** Drop it during diff --git a/truffile/skills/truffile-cli/SKILL.md b/truffile/skills/truffile-cli/SKILL.md index 78b8423..a1f9493 100644 --- a/truffile/skills/truffile-cli/SKILL.md +++ b/truffile/skills/truffile-cli/SKILL.md @@ -46,7 +46,7 @@ Useful checks: truffile doctor --json truffile scan --json --non-interactive truffile connect truffle-1234 --user-id "$TRUFFLE_USER_ID" \ - --json --non-interactive --approval-timeout 120 + --json --non-interactive truffile list devices --json truffile list apps --json ``` @@ -62,7 +62,7 @@ on the physical Truffle. Do not ask them to paste a session token. ```bash truffile scan --json --non-interactive truffile connect truffle-1234 --user-id "$TRUFFLE_USER_ID" \ - --json --non-interactive --approval-timeout 120 + --json --non-interactive truffile list devices --json truffile disconnect truffle-1234 --json truffile disconnect all --json From 380bf70a677f50d87e1da121ab028cd8ce7be482 Mon Sep 17 00:00:00 2001 From: temp-deepshard <304551954+temp-deepshard@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:02:33 -0700 Subject: [PATCH 4/5] Keep agent setup guidance task focused --- README.md | 6 +++--- tests/test_agent_guidance.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f1a73dc..2c94f56 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ do with your Truffle: > Set up the latest Truffile in this workspace, then ****. Follow the > [installation guide](https://docs.truffle.net/sdk/installation). Run -> `truffile load all --json` and `truffile doctor --json`, then follow the -> copied skills. Continue through all work that does not need me. Ask only for -> Symphony onboarding or my User ID, approval on the physical Truffle, +> `truffile load all --json` and `truffile doctor --json`, then follow only the copied skills relevant to the task. +> Continue through all work that does not need me. Ask only for Symphony onboarding or my User ID, +> approval on the physical Truffle, > credentials, or confirmation before deployment or a destructive action. How the pieces fit: diff --git a/tests/test_agent_guidance.py b/tests/test_agent_guidance.py index 5c7d783..19d44ee 100644 --- a/tests/test_agent_guidance.py +++ b/tests/test_agent_guidance.py @@ -16,6 +16,7 @@ def test_setup_prompt_is_goal_first_and_names_human_boundaries(): prompt = compact(README) assert "then ****" in prompt assert "Continue through all work that does not need me" in prompt + assert "follow only the copied skills relevant to the task" in prompt assert "Symphony onboarding or my User ID" in prompt assert "approval on the physical" in prompt From b9c9051a1cc778ff464b248a528bbe3395c7a9e6 Mon Sep 17 00:00:00 2001 From: temp-deepshard <304551954+temp-deepshard@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:48:22 -0700 Subject: [PATCH 5/5] Make container guidance directly discoverable --- tests/test_agent_guidance.py | 1 + truffile/skills/truffile-cli/SKILL.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/tests/test_agent_guidance.py b/tests/test_agent_guidance.py index 19d44ee..7745df0 100644 --- a/tests/test_agent_guidance.py +++ b/tests/test_agent_guidance.py @@ -28,6 +28,7 @@ def test_cli_skill_prefers_machine_contract_and_safe_deletion(): assert "delete my-app --dry-run --json --non-interactive" in CLI_SKILL assert "delete my-app --yes --json --non-interactive" in CLI_SKILL assert "Settings >\nAbout" not in CLI_SKILL + assert "### Running inside a Truffle app container" in CLI_SKILL def test_chat_skill_documents_bounded_compact_output(): diff --git a/truffile/skills/truffile-cli/SKILL.md b/truffile/skills/truffile-cli/SKILL.md index a1f9493..e17c4a9 100644 --- a/truffile/skills/truffile-cli/SKILL.md +++ b/truffile/skills/truffile-cli/SKILL.md @@ -26,10 +26,14 @@ Use this for Truffle device and app lifecycle work. ## Connection Assumptions +### Running inside a Truffle app container + When running inside a Truffle app or agent container, assume the runtime has already provided the session token in env. `truffile connect` should report that the device is already connected. Do not ask the user for tokens. +### Connecting from a computer + For normal laptop use, the user must first onboard their Truffle through the Symphony desktop client: