Tool Publisher
UnreviewedPublish a CLI or knowledge skill to the Adom Wiki for auto-discovery and auto-install — the 2-layer model (private source + public binary on wiki), multi-skill bundling, install-subcommand spec.
Publishing Tools to the Adom Wiki
This skill covers the full lifecycle for making a CLI tool or skill discoverable
and installable by any Adom user — without hardcoding it into gallia/install.mjs,
and without requiring the installing user to have GitHub access to adom-inc/*.
Public vs Private: The Line
Every wiki-published tool has a public side and a private side, and the
demarcation matters for onboarding 3rd-party collaborators:
- Public (wiki-hosted): the compiled binary, the usage docs, the SKILL.md,
screenshots, install hint. Anyone on the Adom platform — including 3rd-party
collaborators with zero GitHub access — can see and install it by hittinghttps://wiki-ufypy5dpx93o.adom.cloud/static/apps/<slug>/<binary>. No auth, no
GitHub token. - Private (GitHub, optional): the source code, build system, issue tracker,
internal design docs. Stays onadom-inc/<repo>with whatever read permissions
you want. The wiki page MAY carry arepolink in metadata for team members
who have GitHub access, but the link is not required and is not used by
the installer.
What this means when you publish:
- Build the binary yourself (
cargo build --release). - Upload it to the wiki as a
docker_binaryasset viaadom-wiki asset upload.
Latest wins — the server auto-deletes any previousdocker_binaryon the same
page before inserting the new one. - Set
metadata.releases.adom_docker.install_hintto acurlcommand that hits/static/apps/<slug>/<asset_name>, notgh release download. - Bump the top-level
version:field in the publish body (→pub_versioncolumn,
semver-validated on the wiki side). - Do not tell users to clone the private repo. The install flow must work
end-to-end from the wiki alone, no GitHub credentials.
What lives where — quick-reference table
| Artifact | Lives in | Why |
|---|---|---|
Source code (*.rs, Cargo.toml, tests, CI config) |
Private GitHub repo (optional) | Internal dev, CI secrets, issue tracking. Choose whether to use GitHub at all. |
| Compiled CLI binary | Public wiki at /static/apps/<slug>/<slug> (uploaded as docker_binary asset) |
Paste-prompt curl must work for any user — no repo access needed. |
| SKILL.md content | Public wiki page (skill_source field) AND embedded in the binary via include_str! |
Users browse it on the wiki; <tool> install drops it to ~/.claude/skills/<slug>/. |
| Install prompt (rendered) | Public — auto-generated on the wiki page from metadata | Users paste it into Claude Code to trigger the install. |
| Discovery triggers & pitch | Public wiki page metadata | Aggregated by /discover into the gallia auto-discover snippet. |
| Screenshots, README, examples, demos | Public wiki page content + assets | Browsable by anyone; drives adoption. |
| Internal design notes, WIP features, roadmap | Private GitHub repo | Not ready for distribution. |
| Secrets, API keys, signing keys | Neither — env vars / 1Password / CI secrets | Never committed to either. |
Rule of thumb: if a user on a fresh container needs it to install or run your
tool, it goes on the wiki. Everything else stays in the private repo (if you use
one at all).
Architecture: 2-Layer Distribution
Layer 1: Source Code (private GitHub repo, optional link only)
↓ cargo build --release + adom-wiki asset upload
Layer 2: Adom Wiki (public: binary asset + discovery metadata + install prompt)
↓ gallia/hooks/refresh-wiki-catalog.mjs audits installed versions every 30 min
↓ stale tool? Claude asks user "Shall I upgrade?"
User Container (binary upgraded from wiki)
Key principle: gallia/install.mjs is for core infrastructure only (adom-cli,
adom-wiki, viewer, MCP servers). New tools use wiki auto-discovery instead —
they get discovered and installed on-demand, and the 30-min refresh hook keeps
users' installed versions in sync with the wiki's pub_version.
Gallia's only role for new tools is carrying the auto-discover snippet. Not
source, not binary, not SKILL.md, not docs — none of it lives in gallia. The
snippet is regenerated from wiki metadata on every container setup and on every
30-min hook tick. Ship updates by re-publishing the wiki page, not by opening a
gallia PR.
When to Use Each Layer
| Distribution | When | Example |
|---|---|---|
| gallia/install.mjs | Core infra every container needs | adom-cli, adom-wiki, viewer |
| Wiki auto-discovery | Tools users install on-demand | adom-molecule, shotlog, adom-tsci |
| gallia/skills/ | Cross-cutting reference skills not tied to one app | being phased out — prefer wiki |
Prerequisites
Before publishing, you need:
- A working CLI (see
adom-cli-designskill for Rust CLI conventions) - A SKILL.md embedded in the binary (see
skill-creatorskill) - A built
target/release/<tool>binary — where you build it is up to you.
A privateadom-inc/<tool>GitHub repo is the usual home for source, but
you do NOT need a GitHub release — the binary goes to the wiki. - The
adom-wikiCLI installed - A
<tool> --versioncommand that prints a semver line (defaults to--version;
override viametadata.releases.adom_docker.version_commandif your CLI uses
a different flag)
Step 1: Build the CLI
Follow the adom-cli-design skill. Key requirements:
- Rust with
clap,ureq,serde_json OK:/ERROR:output formatinstallsubcommand that deploys SKILL.md viainclude_str!healthsubcommand if it talks to a server.gitignorewithtarget/
# Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
ureq = { version = "2", features = ["json"] }
clap = { version = "4", features = ["derive", "env"] }
[profile.release]
strip = true
lto = "thin"
Build:
cargo build --release
sudo cp target/release/my-tool /usr/local/bin/
my-tool install # deploys SKILL.md to ~/.claude/skills/my-tool/
Step 2: Put source on GitHub (optional) and upload binary to the wiki
2a. Private source repo (optional)
Source code stays private. You choose whether to host it on GitHub at all; it's
fine to just keep the source in your local checkout. If you do use GitHub:
gh repo create adom-inc/my-tool --private --description "One-line description"
cd /path/to/my-tool
git init && git remote add origin https://github.com/adom-inc/my-tool.git
echo "target/" > .gitignore
git add -A && git commit -m "Initial release: my-tool v0.1.0"
git branch -M main && git push -u origin main
Do NOT gh release create. The compiled binary does not belong in a GitHub
release anymore — it goes to the wiki, where it's actually installable by people
without GitHub access.
2b. Upload the binary to the wiki
# Publish a minimal page first (Step 3 fills in the full metadata).
# If you're doing this as part of an update (page already exists), skip the
# publish and go straight to the asset upload.
adom-wiki asset upload apps/my-tool \
--asset-type docker_binary \
--file target/release/my-tool \
--caption "v0.1.0 build for adom docker"
The wiki auto-deletes any previous docker_binary on this page before storing
the new file, so this command is idempotent — run it again on every release.
The canonical public download URL is:
https://wiki-ufypy5dpx93o.adom.cloud/static/apps/my-tool/my-tool
Verify it's reachable without any credentials:
curl -I https://wiki-ufypy5dpx93o.adom.cloud/static/apps/my-tool/my-tool
# expect HTTP/1.1 200 OK, content-type: application/octet-stream
Step 3: Publish Wiki Page
Publish as page type app with full metadata including discovery triggers.
3a. Write the wiki content
Create a markdown file (/tmp/my-tool-wiki.md) with:
- What it does (1-2 paragraphs)
- What the
curl-based install prompt does for them (they paste it, Claude runs it) - Quick start examples
- Link to the repo (optional — informational only)
3b. Publish with metadata
Critical: Include metadata in the initial publish. The v1 publish endpoint
accepts a monotonically-increasing version: field and overwrites content,brief, and skill_source on re-publish. Metadata updates, however, are best
done via the dedicated endpoint (see 3c below) or by delete+recreate if the
direct metadata edit doesn't stick — this gap is being closed; see the
"Wiki-side work" section at the bottom of this page.
WIKI_URL="https://wiki-ufypy5dpx93o.adom.cloud"
curl -s -X POST "$WIKI_URL/api/v1/pages" \
-H "Authorization: Bearer adom-wiki-dev-2025" \
-H "Content-Type: application/json" \
-d '{
"type": "app",
"slug": "my-tool",
"title": "My Tool Name",
"brief": "One-line description for search results and page header.",
"content": "... markdown content ...",
"skill_source": "... contents of SKILL.md ...",
"metadata": {
"repo": "adom-inc/my-tool",
"repo_visibility": "private",
"releases": {
"adom_docker": {
"asset_name": "my-tool",
"install_hint": "curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/my-tool/my-tool -o /usr/local/bin/my-tool && chmod +x /usr/local/bin/my-tool && my-tool install"
}
},
"discovery_triggers": [
"trigger phrase 1",
"trigger phrase 2",
"trigger phrase 3"
],
"discovery_pitch": "One sentence explaining what this tool does and why you want it."
},
"version": "0.1.0",
"changelog": "Initial release"
}'
Notes on the fields:
- Top-level
version→pub_versioncolumn on the page. Semver-validated on
the wiki side. This is the single source of truth for the tool's version.
Gallia's 30-min refresh hook readspub_versiondirectly; it ignoresmetadata.version. Don't bother settingmetadata.version. install_hintmust be self-contained (no GitHub access, no tokens). Usecurl -fsSL <wiki static URL>— nevergh release download.repois purely informational. Team members with GitHub access may follow
it to the source; 3rd-party collaborators will just ignore it.- If your tool's
--versionflag isn't the default, also setmetadata.releases.adom_docker.version_commandto the exact shell command
gallia should run (e.g."my-tool version --short").
3c. Verify
# Check the page exists and has metadata
adom-wiki page get apps/my-tool | python3 -c "
import sys, json
d = json.load(sys.stdin)
meta = json.loads(d['page']['metadata'])
print('Triggers:', meta.get('discovery_triggers'))
print('Pitch:', meta.get('discovery_pitch'))
print('Install:', meta.get('releases',{}).get('adom_docker',{}).get('install_hint'))
"
# Check the discover page includes your tool
# Visit: https://wiki-ufypy5dpx93o.adom.cloud/discover
Metadata Fields Reference
Required for Auto-Discovery
| Field | Type | Purpose |
|---|---|---|
discovery_triggers |
string[] | Phrases users might say. Claude matches these to suggest the tool. |
discovery_pitch |
string | One-sentence hook shown when Claude suggests the tool. |
Required for Auto-Install
| Field | Type | Purpose |
|---|---|---|
releases.adom_docker.asset_name |
string | Binary filename on the wiki asset (must match adom-wiki asset upload --file's filename). Also used as the command -v check and default --version bin. |
releases.adom_docker.install_hint |
string | Full install command. Must be self-contained (no GitHub auth). Use curl -fsSL https://wiki-.../static/apps/<slug>/<asset>. |
Optional
| Field | Type | Purpose |
|---|---|---|
releases.adom_docker.version_command |
string | Shell command to check the installed version (default: <asset_name> --version). Output must contain a semver like 1.2.3. |
repo |
string | GitHub repo (owner/name) — informational, not used by installer |
repo_visibility |
string | "private" or "public" |
releases.windows |
object | Windows installer info (for desktop apps) |
NOT used anymore
metadata.version— ignored. Use the top-levelversion:field, which
writes to thepub_versioncolumn.
How Auto-Discovery + Continuous Sync Works
- The wiki's
/discoverpage aggregates all pages withdiscovery_triggersmetadata. gallia/hooks/refresh-wiki-catalog.mjsfetches/discoverand writes the
concatenated SKILL.md snippet to~/.claude/skills/adom-wiki-discover/SKILL.md.- The same script also fetches
/api/v1/pages, walks every page with areleases.adom_dockerentry, HEAD-checks the binary's public download URL,
runs the tool's version command, and comparesinstalledtopub_version. gallia/hooks/check-updates.shruns the refresh script every ~30 min (via theUserPromptSubmithook). On success, it updates~/.adom/last-wiki-check.- If any installed tool is older than its wiki
pub_version, the hook injects a<system-reminder>telling Claude to ASK the user "Shall I upgrade
from→ ?". On confirmation, Claude runs the install_hint
(whichcurls the wiki asset). On decline, Claude drops it for the session. install.mjsalso calls the refresh script on container setup, so a fresh
container starts with the current catalog instead of waiting 30 min for the
first hook tick.
Gallia never downloads tools from GitHub anymore. Every install / upgrade path
is rooted in the wiki — which means any 3rd-party user with access to the Adom
container gets the same install experience as a team member.
How the Install Prompt Works
The wiki renders an "Install this app" block on every app page. The prompt text is
auto-generated by renderInstallPrompt() in wiki/lib/templates.js based on the
page type and metadata.
For app pages, it uses releases.adom_docker.install_hint to build a prompt like:
I want to install the "My Tool" app from the Adom Wiki. Run this:
curl -fsSL https://wiki-.../static/apps/my-tool/my-tool -o /usr/local/bin/my-tool && chmod +x /usr/local/bin/my-tool && my-tool install
Then verify the install works.
Users copy this prompt and paste it into Claude Code, which executes the install.
Writing Good Discovery Triggers
Think about what a user would say when they need your tool:
Good triggers (specific, action-oriented):
["create molecule", "import kicad files", "upload fusion files",
"molecule from kicad", "optimize molecule 3d"]
Bad triggers (too generic, would match everything):
["help", "tool", "create", "upload"]
Include 8-15 triggers covering:
- The primary action ("create molecule")
- Input formats ("import kicad files", "upload fusion files")
- Alternate phrasings ("molecule from kicad", "kicad to molecule")
- Specific features ("optimize molecule", "blender optimization")
Writing a Good Discovery Pitch
One sentence that answers: "Why would I want this?"
Good: "Import KiCad, Fusion 360, or EasyEDA design files into Adom molecules
with one command. Handles file upload, 3D optimization, and molecule management."
Bad: "A CLI tool for molecules."
The install subcommand: what it actually needs to do
The paste-prompt curl ... && my-tool install is the entire onboarding surface
for a new user. Don't under-spec this subcommand — users won't forgive a
half-broken install that leaves them to read a --help and figure it out.
Required responsibilities, in order:
Check system prereqs. If your tool needs
bun,node,ffmpeg,python3.11+, or anything else the base container doesn't already have,
check for it up front and print a singleERROR:line with the exact
install command the user should run. Never proceed past a missing prereq —
the user's first experience must not be a cryptic runtime crash.if which::which("bun").is_err() { eprintln!("ERROR: `bun` is required but not found."); eprintln!("Install with: curl -fsSL https://bun.sh/install | bash"); std::process::exit(1); }Deploy the binary to
~/.local/bin/<tool>(or/usr/local/bin/if thecurlin the install hint put it there — yourinstallsubcommand should
handle the case where the binary is re-run from either location).Deploy every bundled SKILL.md to
~/.claude/skills/<skill-name>/SKILL.md.
Useinclude_str!at compile time so each skill lives alongside the source
in the private repo. Multi-skill apps (next section) drop multiple files
here.Install shell completions for the user's current shell. Silent
best-effort — if the shell's completion dir doesn't exist, skip.
Completions significantly improve discoverability of subcommands for
non-programmer users who don't reflexively run--help.my-tool completions bash > ~/.local/share/bash-completion/completions/my-tool 2>/dev/null || true my-tool completions zsh > ~/.zsh/completions/_my-tool 2>/dev/null || trueWrite an
OK:line per action taken and a final summary. Mirror theadom-cli-designoutput format. Users and Claude both readinstall
output to confirm success.Be idempotent. Re-running
installshould update everything to match
the current binary (newer SKILL.md, newer completions) and printOK:for
each step, not error out because files exist.
Minimum viable output:
OK: prereqs checked (bun 1.1.30, gh 2.55.0)
OK: binary at /usr/local/bin/my-tool
OK: deployed 2 skill(s) to ~/.claude/skills/
OK: bash completions installed
OK: my-tool ready. Try `my-tool --help`.
Multi-skill apps: bundling more than one SKILL.md
Some apps ship a reference skill (how to drive the app's own commands)
and a recipe skill (higher-level workflow that uses the app). The
archetype is adom-tsci, which ships both:
adom-tsci— reference skill for the binary's CLI (start, reload, open, …)adom-tscircuit— recipe skill for designing Adom Molecules in tscircuit
using theadom-tscipreview workflow
Both belong in the same repo (adom-inc/adom-tsci) and both get deployed by
the same adom-tsci install subcommand. Layout:
adom-inc/adom-tsci/
├── Cargo.toml
├── src/
│ └── main.rs // include_str! both SKILL.mds
├── skills/
│ ├── adom-tsci/
│ │ └── SKILL.md // reference skill
│ └── adom-tscircuit/
│ └── SKILL.md // recipe skill
└── README.md
In main.rs:
const SKILL_REFERENCE: &str = include_str!("../skills/adom-tsci/SKILL.md");
const SKILL_RECIPE: &str = include_str!("../skills/adom-tscircuit/SKILL.md");
fn install() {
write_skill("adom-tsci", SKILL_REFERENCE);
write_skill("adom-tscircuit", SKILL_RECIPE);
// ... completions, prereqs, etc
}
Rules:
- One wiki page per app, not per skill. The wiki page's
skill_source
field carries the primary (reference) skill; secondary skills are
documented in the page content and shipped in the binary. - Each SKILL.md has its own discovery triggers in its frontmatter so
Claude loads the right one for the right trigger phrase. The wiki page
metadata'sdiscovery_triggerscovers the install trigger ("install
adom-tsci", "preview tscircuit in webview", etc.). - Keep the recipe skill tightly scoped. If a recipe skill grows features
that aren't specific to this app, split it out into its own wiki page.
Example: shotlog (reference implementation for the wiki-hosted model)
- Source (private):
adom-inc/shotlog— source stays here, no public release. - Wiki page:
apps/shotlog - Wiki asset:
docker_binaryuploaded viaadom-wiki asset upload, public URLhttps://wiki-ufypy5dpx93o.adom.cloud/static/apps/shotlog/shotlog - Discovery triggers: 14 phrases (screenshot log, visual debug loop, ...)
- Install:
curl -fsSL <wiki URL>/static/apps/shotlog/shotlog -o /usr/local/bin/shotlog && chmod +x /usr/local/bin/shotlog && shotlog install - NOT in install.mjs — discovered and installed on-demand via the wiki
- Auto-upgrade: gallia's 30-min refresh hook compares installed
shotlog --version
against the wikipub_versionand offers an upgrade when they diverge
Updating a Published Tool
To release a new version:
# 1. Build the new binary
cargo build --release
# 2. Push the source change to the private repo (optional — if you use one)
git commit -am "..." && git push origin main
# 3. Upload the new binary to the wiki. The previous docker_binary asset on
# this page is auto-deleted before the new one is stored.
adom-wiki asset upload apps/my-tool \
--asset-type docker_binary \
--file target/release/my-tool \
--caption "v0.2.0 build for adom docker"
# 4. Bump the page's pub_version (and install_hint if it changed).
# The publish endpoint accepts a monotonically-greater version and
# overwrites content / skill_source / brief / title. If you also need
# to change metadata and the field-edit path is flaky, fall back to
# DELETE + recreate. See "Wiki-side work" below.
adom-wiki page publish apps/my-tool \
--title "My Tool Name" \
--brief "..." \
--body-md /tmp/my-tool-wiki.md \
--skill-source /path/to/SKILL.md \
--version 0.2.0 \
--changelog "..."
# 5. Update metadata (discovery triggers, install hint, etc.)
adom-wiki page edit apps/my-tool \
--field metadata \
--body-md /tmp/metadata.json
After republishing, the next time any Adom container's 30-min hook ticks, the
refresh script sees the new pub_version and (if the user has the old binary
installed) injects a system-reminder offering an upgrade. Propagation is
automatic from this point — you don't need to do anything else.
Checklist
Before publishing:
- CLI builds clean with
cargo build --release -
my-tool --versionprints a semver (or you setversion_commandin the wiki metadata) -
my-tool healthworks (if applicable) -
my-tool installdeploys SKILL.md correctly, checks prereqs, installs completions -
my-tool installis idempotent (re-running just re-syncs everything) - Binary uploaded to the wiki as
docker_binary -
curl -I https://wiki-.../static/apps/<slug>/<bin>returns 200 with no auth - Wiki page has top-level
version: "x.y.z"(→pub_version) - Wiki page has
discovery_triggersanddiscovery_pitchin metadata - Wiki page has
releases.adom_docker.install_hintstarting withcurl -fsSL https://wiki-— notgh release download - Install prompt on wiki page renders the new curl-based command
- Tool appears on
/discoverpage - End-to-end install tested in a zero-credential environment — a fresh
container with no GitHub token must be able to run the install_hint and
get a working binary - NOT added to install.mjs (unless it's core infrastructure)
Wiki-side work (tracked separately)
The wiki service is still closing a couple of gaps. Both affect smoothness of
the publish → update → distribute loop; neither blocks shipping a new tool
today. Workarounds below apply until they land.
Metadata-only updates on an existing page. The
adom-wiki page edit --field metadatapath is the intended update endpoint, but its propagation
to/discoverisn't fully deterministic yet. Workaround: bumppub_version
on a full re-publish, orDELETE+ re-POST if metadata doesn't stick.adom-wiki asset upload --asset-type docker_binaryis the documented
path, but if youradom-wikiCLI build doesn't surface that value in its--asset-typeenum, fall back to the raw curl upload against/api/v1/pages/<slug>/assetsuntil the CLI catches up.
These are tracked on the wiki repo. The pattern described in this skill is the
forward-compatible one — don't code around either gap in ways that would break
once they're fixed.
AI Hints: Making CLIs Smart for AI Callers
When AI (Claude) calls your CLI, it needs contextual guidance on what to do next. Add _hint fields to JSON responses that tell the AI:
- What went wrong and how to fix it
- What to do after a successful command
- What might go wrong next
This is the single most important pattern for making a CLI work well with AI. Without hints, the AI guesses. With hints, it acts correctly on the first try.
Pattern 1: Success hints — tell AI the next step
{
"success": true,
"output": "Exported gerbers to C:/tmp/gerbers.zip",
"_hint": "Files saved on Windows. Use pull_file to get them to Docker: pull_file '{\"filePaths\":[\"C:/tmp/gerbers.zip\"],\"saveTo\":\"/tmp/mfg\"}'"
}
The AI reads _hint and knows to call pull_file — without this, it would just report "exported" and stop.
Pattern 2: Warning hints — tell AI what can go wrong
{
"success": true,
"output": "Opened BQ25792 from cloud",
"_hint": "WARNING: May trigger 'Select Electronics Design File' dialog when switching to electronics workspace. If next command fails with 'add-in not responding', check fusion_window_info for blocking dialogs. Try fusion_send_key escape to dismiss."
}
The AI is now primed to handle the dialog if it appears, instead of getting stuck.
Pattern 3: Verification hints — tell AI to check its work
{
"success": true,
"output": "Launched schematic editor",
"_hint": "WARNING: KiCad may show modal dialogs (save prompts, file warnings) that block further commands. ALWAYS check kicad_window_info for hasModalDialogs after this command. If true, use kicad_screenshot_all to capture all windows, pull_file to get screenshots, then read the dialog to decide how to handle it."
}
This turns a simple "opened" response into a full debugging workflow the AI follows automatically.
Pattern 4: Error diagnosis — auto-attach context on failure
// In your CLI code: when a command fails, try to diagnose WHY
let error_str = map.get("error").and_then(|v| v.as_str()).unwrap_or("");
if error_str.contains("not responding") {
// Auto-run diagnostic command
let diag = run_diagnostic_command();
enriched.insert("_hint", json!("Add-in blocked by modal dialog. Run window_info to find it, screenshot it, dismiss with send_key."));
enriched.insert("_diagnosis", diag);
}
The AI gets the error + diagnosis + recovery steps in one response — no back-and-forth needed.
Pattern 5: Prerequisite hints — tell AI what must be true first
{
"success": false,
"error": "Not an Electron document",
"_hint": "Requires Electronics workspace active (isElectronics: true in get_app_state). The active tab is 3D PCB not PCB Editor. Switch with activate_document or open the .brd file."
}
Implementation: where to add hints
Add hints in the CLI's command routing layer — the single point where responses pass through before being printed to stdout. Don't put them in the backend/bridge; the CLI is the AI's interface.
// In commands.rs — match on command name and success/failure
match command {
"export_gerbers" if success => add_hint("Files on Windows. Use pull_file..."),
"open_schematic" if success => add_hint("WARNING: modals may appear..."),
_ if error.contains("not responding") => add_hint("Blocked by dialog..."),
}
Pattern 6: Modal-first loops — teach AI to poll, not sleep
Desktop apps show modal dialogs that block everything. The AI's natural instinct is sleep 10 — but that wastes time and misses dialogs. Teach it to poll:
{
"error": "Add-in not responding",
"_hint": "BLOCKED by modal dialog. DO NOT sleep — check immediately: (1) window_info → find dialogs, (2) screenshot each → read text, (3) click Yes/OK to dismiss. IMPORTANT: Dialogs CASCADE — after dismissing one, check for MORE before proceeding. Loop until app_state returns success."
}
Key phrases that change AI behavior:
- "DO NOT sleep" — overrides the default instinct
- "check immediately" — creates urgency
- "Dialogs CASCADE" — prevents the AI from assuming one dismissal fixes everything
- "Loop until" — gives a clear termination condition
Rules for good hints
- Be specific — "Use pull_file with filePaths array" not "transfer the file"
- Include example commands — Show the exact CLI call the AI should make
- Warn about traps — "NOTE: Enter does NOT work on this dialog, use Escape"
- Chain commands — "After this, run X, then Y, then Z"
- Explain prerequisites — "Requires Electronics workspace active"
- Override bad instincts — "DO NOT sleep" when the AI should poll instead
- Keep it under 200 chars for simple hints, longer for complex recovery flows
Related Skills
adom-cli-design— Rust CLI conventions (output format, clap patterns, port registration)skill-creator— How to write SKILL.md filesadom-wiki— Wiki CLI for publishing and managing pages