Generate a reusable, platform-agnostic Python SDK for any task domain using the Task as Code (TaC) pattern — the generalized form of Perplexity's Search as Code architecture. Use this skill whenever someone wants to make a complex multi-step task reusable and programmable: building an SDK for a domain (design systems, data analysis, document processing, code review, market research, competitive intelligence), creating a workflow that benefits from parallelism and composable primitives, or packaging agentic task logic so any LLM can orchestrate it via generated code. Trigger on: build me an SDK for X, make X programmatic, create a reusable workflow for X, turn X into code, generate a design system SDK, I want to automate X with an LLM, package this as a reusable skill, or any request to structure a complex domain task as composable Python building blocks.
Generate a reusable, platform-agnostic Python SDK for any task domain using the Task as Code (TaC) pattern — the generalized form of Perplexity's Search as Code architecture. Use this skill whenever someone wants to make a complex multi-step task reusable and programmable: building an SDK for a domain (design systems, data analysis, document processing, code review, market research, competitive intelligence), creating a workflow that benefits from parallelism and composable primitives, or packaging agentic task logic so any LLM can orchestrate it via generated code. Trigger on: build me an SDK for X, make X programmatic, create a reusable workflow for X, turn X into code, generate a design system SDK, I want to automate X with an LLM, package this as a reusable skill, or any request to structure a complex domain task as composable Python building blocks.
Task as Code (TaC)
A meta-skill for creating domain-specific, reusable Python SDKs that expose task
primitives for LLM orchestration — the platform-agnostic generalization of Perplexity's
Search as Code (SaC) architecture.
What is Task as Code?
Traditional LLM usage treats a task as a single prompt: hand the model a goal and expect
everything in one context window. TaC inverts this: instead of a monolithic prompt, you
expose the task's building blocks as a Python SDK. A control-plane LLM then generates
Python code that composes those building blocks into a bespoke pipeline for each specific
request.
The three layers of every TaC SDK:
Control Plane — An LLM generates Python orchestration code tailored to each request
State Layer — Filesystem-based persistence for multi-turn agentic workflows
This gives you composability, efficiency (parallelism, batching), reusability across
projects, and adaptability — the control-plane LLM designs a new pipeline per request,
not a fixed one.
Read references/pattern-theory.md for the full TaC architecture deep dive before starting.
When to Create a TaC SDK
TaC is the right pattern when:
The task has 5+ repeatable atomic operations (fetch, filter, transform, score, etc.)
Workflows vary enough per request that a single prompt is inefficient or fragile
The task benefits from parallelism or multi-turn state (many sub-calls per task)
You want the task reusable across projects as an installable packaged skill
It's overkill when the task is a single LLM call with minor variation. Use a prompt
template in that case.
Step 1: Analyze the Task Domain
Before writing any code, reason carefully about the domain. Ask:
What is the goal? (e.g., "generate a design system", "analyze a codebase")
What are the atomic operations? List every distinct sub-operation the task requires
Which operations are deterministic vs. intelligence-requiring?
Named with verbs: fetch_, filter_, dedupe_, score_, transform_, batch_
Typed parameters and return types throughout
Tier 2 — Composite Operations (higher level, common patterns):
Combine 2–4 atomics into common workflows
May include one LLM sub-call
Named for the compound action: fetch_and_rank_, search_and_extract_
Domain type → primitive pattern mapping:
Domain Type
Example
Core Primitives
LLM Primitives
Retrieval
Web research
fetch_, filter_, dedupe_, rank_
extract_, verify_
Generation
Design systems
parse_spec_, validate_, assemble_
plan_, generate_, refine_
Analysis
Code review
load_, profile_, segment_, score_
classify_, summarize_
Transformation
ETL / format conversion
read_, map_, normalize_, write_
enrich_, infer_
Step 3: Scaffold the SDK Structure
Run the scaffold script to create the folder structure:
python scripts/scaffold_sdk.py <task-name>
This creates:
<task-name>-sdk/
├── SKILL.md ← Consumer skill (generate last, in Step 6)
├── sdk/
│ ├── __init__.py ← Public API exports
│ ├── core.py ← Tier 1 atomic primitives (deterministic)
│ ├── llm.py ← Tier 2 LLM-powered operations + embedded prompts
│ ├── orchestrate.py ← Agentic loop + TaskState + filesystem persistence
│ └── utils.py ← Shared helpers (call_llm, parse_json, retry, batch)
├── examples/
│ ├── simple_usage.py ← Stateless single-turn example
│ └── agentic_usage.py ← Multi-turn agentic example with state save/load
├── prompts/
│ └── system.md ← System prompt for the control-plane LLM
└── requirements.txt
Step 4: Implement the SDK Modules
sdk/core.py — Atomic Primitives
Write pure Python functions. Rules:
Every function has type hints + complete docstring (Args/Returns/Example)
No global state; all dependencies are explicit parameters
Functions are idempotent where possible
Raise descriptive exceptions, never silently fail
# Pattern for core.pydeffetch_items(
source: str,
limit: int = 10,
filters: dict[str, str] | None = None,
) -> list[dict]:
"""Fetch items from source with optional filtering.
Args:
source: URL or identifier for the data source.
limit: Maximum number of items to return.
filters: Optional key-value filters to apply.
Returns:
List of item dicts with at minimum {"id", "content"} keys.
Example:
items = fetch_items("https://api.example.com/data", limit=20)
"""
...
sdk/llm.py — LLM-Powered Operations
Embed prompts as module-level constants. The most important rule: each function owns
exactly ONE _PROMPT_* constant, never assembled inline.
# Pattern for llm.py
_PROMPT_CLASSIFY = """\
Classify the item into one of: {categories}.
Return JSON: {{"category": "<choice>", "confidence": <0-1>, "reason": "<sentence>"}}
Item: {item}"""@dataclassclassClassifyResult:
category: str
confidence: float
reason: strdefclassify_item(item: str, categories: list[str], client=None) -> ClassifyResult | None:
"""Classify an item into one of the provided categories. ..."""
prompt = _PROMPT_CLASSIFY.format(categories=", ".join(categories), item=item)
raw = call_llm(prompt, client=client)
return parse_json_robust(raw, ClassifyResult)
defclassify_many(items, categories, concurrency=8, client=None) -> list[ClassifyResult | None]:
"""Batch-classify items using thread-pool concurrency. ..."""with ThreadPoolExecutor(max_workers=concurrency) as pool:
return [f.result() for f in [pool.submit(classify_item, i, categories, client) for i in items]]
Provide both _single and _many variants for every LLM operation. Batch functions
are the primary path for production use.
sdk/orchestrate.py — Agentic Loop + State
See references/sdk-design.md §State Management for the full TaskState schema and
turn-loop pattern. At minimum implement:
call_llm must be provider-agnostic: auto-detect ANTHROPIC_API_KEY → use anthropic
SDK; else OPENAI_API_KEY → use openai SDK; else raise LLMConfigError.
See references/sdk-design.md for complete implementation patterns.
Step 5: Write Examples and System Prompt
examples/simple_usage.py — 3–5 core SDK functions, stateless, runnable with
python examples/simple_usage.py (with env vars set).
examples/agentic_usage.py — demonstrates run_task_loop, state save/load,
and resume_task_loop for interrupted recovery.
prompts/system.md — the system prompt the control-plane LLM reads when using
the SDK. Must stay under 2,000 tokens. Structure: