Skill authoring guide
The technical reference for writing skills. What tools the agent has, what triggers exist today, and how to write bodies that map cleanly to both.
How skills work, in one paragraph
A skill is a doc with type = skill. Its body is plain English. When you click Activate, a “setup” agent reads the body and derives a wiring (which event to listen for, what filter to apply). When a matching trigger fires — or you click Run— an “execution” agent runs the body with access to a toolbelt of named tools it can call to read data and take action. Both setup and execution share the same engine; the only difference is which toolbelt they get.
The lifecycle
| State | Meaning | Primary action |
|---|---|---|
| Inert | Doc exists. No setup has been run. | Activate |
| Draft | Setup produced wirings, but they aren't firing yet. | Activate (flip wirings on) |
| Live | At least one wiring is active. Triggers fire the skill. | Run (ad-hoc) |
There's a fourth quasi-state: Live · stale. This appears when you've edited the body since the last Activate. The old wiring keeps firing, but the body has drifted. Click Re-derive wiring to refresh.
Editing the body never automatically re-runs setup. That's deliberate — auto-fire on save thrashed during testing (every keystroke was an LLM call). Re-derive is explicit.
Triggers — what fires a skill today
Every skill needs to know when to fire. The setup agent reads your body and registers one or more triggers. Today, exactly one trigger source is supported.
card.moved
Fires when any card on any board in your workspace changes stage.
Filter fields— the setup agent picks based on your body's wording:
toStageName— the name of the stage the card moved TOfromStageName— the name of the stage the card moved FROMboardId— restrict to one boardtoStageId,fromStageId— restrict to one specific stage by ID
Filters are shallow equality. “When a card moves to Done” → likely { toStageName: "Done" }. “When a card moves from Backlog to In Progress” → likely { fromStageName: "Backlog", toStageName: "In Progress" }.
Not supported as triggers (yet)
- Cron — “every Monday at 9am” doesn't work yet
- Webhooks from external systems — no inbound URL minting
- Other SP events — feedback created, person added, doc edited, comment posted don't emit yet
- Multi-condition logic across triggers beyond simple shallow-equality filters
If you write a body that relies on an unsupported trigger, the wiring will be empty or partial. You can still use Run Now to fire the skill manually.
Execution toolbelt
When the skill fires, the agent has access to these tools. Names use underscores (not dots) because Anthropic's tool-name regex requires it. All current tools are SP-internal — they read and write data in your workspace.
sp_cards_get
Get a card's full details (title, description, stage, board, linked-docs preview).
{ cardId: string }sp_cards_list_linked_docs
List docs explicitly linked to a card (via the linking UI). Optional docType narrows to one category.
{ cardId: string, docType?: string }sp_docs_list_linked_people
For a given doc, return the people linked to it (e.g. the customers behind a feedback doc).
{ docId: string }sp_docs_search
Full-text search across docs in the workspace. Useful when you want docs ABOUT a topic, not just docs explicitly linked.
{ query: string, docType?: string, limit?: number }sp_cards_search
Full-text search across all cards in all boards in the workspace.
{ query: string, limit?: number }sp_releases_create
Create a release doc in the workspace. Returns the new release's docId.
{ title: string, content: string (markdown) }sp_emails_draft
Save an email draft addressed to a specific person. The draft is NOT sent automatically — it goes to drafts for review.
{ personId: string, to: string, subject: string, body: string }sp_run_save_summary
Save a 1-3 sentence summary of what this run accomplished. Call exactly once at the end before ending the turn.
{ summary: string }What you can't do yet
The execution toolbelt does NOT include:
- Sending emails — drafts only. No sp_emails_send.
- External APIs — no Gmail, Slack, GitHub, or arbitrary HTTP. Actions stay in SP.
- Modifying cards — no update, move, or create. (Coming.)
- People / org CRUD — can't create or update people or orgs from inside a skill.
- Comments — can't post comments to anything.
- Anything cross-workspace — skills only see and modify their own workspace.
If you write a skill that asks for any of these, the agent will either ignore the step or improvise around it. The summary should mention what couldn't be done — but don't rely on that.
Example skill bodies
Real shapes that work today.
Example 1 — Release from linked feedback (explicit form)
When a card moves to Done:
1. Read the card's full details (sp_cards_get).
2. Find feedback docs linked to the card
(sp_cards_list_linked_docs with docType="feedback").
3. For each feedback doc, find the linked people
(sp_docs_list_linked_people).
4. Create a release doc summarizing what shipped
(sp_releases_create) — lead with what users can now do.
5. For each unique customer, draft a personal email
(sp_emails_draft) — short, address them by name,
reference their feedback if appropriate.
6. Save a one-sentence summary (sp_run_save_summary).The agent follows this almost verbatim. Use it when you want predictable behavior.
Example 2 — Release + search-based feedback discovery
When a card moves to Done, write a release and notify the
customers whose feedback shaped it.
To find the right customers, don't just look at linked
feedback — also SEARCH recent feedback for content related
to the card's title and description. Combine linked-feedback
customers and search-result customers, dedupe, then draft
each one a personal email about the release.Less rigid than Example 1, but explicitly tells the agent to use both link-traversal AND search.
Example 3 — On-demand customer outreach (Run-Now only)
For the most recent 5 feedback docs in this workspace:
- Find the customer who left each (sp_docs_list_linked_people).
- Draft each customer a short thank-you email acknowledging
their feedback and asking if they'd be open to a
15-minute call this week.
After drafting, save a summary listing who got emails.No trigger — useful only via Run Now. Activate is a no-op. Good pattern for one-off outreach.
Best practices
Be explicit about which tools to use
Vague: “find feedback related to this card.” Better: “search feedback for themes related to the card's title.” The first might be interpreted as “LINKED feedback.” The second points the agent at sp_docs_search. Tool ambiguity is the most common reason skills don't do what you expected.
Order your steps
The agent generally follows the order you write things in. If you put “save summary” before “draft emails,” the agent may save the summary too early. End with sp_run_save_summary.
Keep the scope bounded
The execution loop has a max-turn safety limit (currently 12 turns). Skills that fan out to dozens of items can exceed it. Narrow the scope (“most recent 5”) or split into multiple skills.
Don't promise unsupported features
If you ask for “send emails directly” or “post to Slack,” the agent might try, fail silently, and you'll wonder why nothing happened. Stick to what's documented above.
Use specific verbs
Verbs the agent recognizes well: search, read, find linked, list, create, draft, save. Verbs that may not behave as expected: notify (draft email? post comment?), update (no update tools), publish(the agent can't publish for you).
Iterate via Run Now
The fastest dev loop is: write body → click Run Now → inspect transcript → tweak body → repeat. You don't need to Activate while iterating. Once it's right, Activate to start listening on real triggers.
How to invoke a skill
- Activate + trigger — set up the wiring, wait for the event (today:
card.moved). The typical autonomous pattern. - Run Now button — execute once immediately. Empty payload. Good for testing and on-demand skills.
- External agent execution — Claude Code (or any agent with the SP MCP) can read the skill body via
get_docand execute its instructions directly using SP MCP tools. Coming: a dedicatedsp.skills.start_runMCP tool that runs through SP's engine with full run-history tracking.
Stuck? Confused? Hit something undocumented?
The skills system is new. If your skill does something surprising, the transcript on the run history (/app/<slug>/skills/runs) is the best debugging surface — it shows every tool call, every argument, every result. If something documented here doesn't work in practice, that's a bug we'd want to know about.