Tool composition patterns
Three recipes that show up over and over — scrape-and-enrich, process-and-transform, and remember-across-runs.
You'll combine tools far more often than you'll use one alone. Three patterns cover most production agents.
Pattern 1 — Scrape and enrich
Browser + HTTP. Use the browser when there's no API; use HTTP when there is. Combine when the API needs a value you have to scrape first.
Example: "Research Acme Corp."
1. jettson_browser_navigate https://acme.com
2. jettson_browser_extract_text — find the company's GitHub org slug
3. jettson_http_request GET https://api.github.com/orgs/<slug>
4. jettson_http_request GET https://api.github.com/orgs/<slug>/repos
5. Mind reasons over both data sources, produces a dossierThe browser does the unstructured "find the identifier" step; the HTTP tool does the structured pulls.
Pattern 2 — Process and transform
Files + Shell. When the task involves doing real work on data — filtering a CSV, transforming JSON, building a tarball — keep the data on disk and let the shell do what it's good at.
Example: "Filter a 50K-row CSV down to active users and email a summary."
1. jettson_http_request GET https://internal-api.example.com/users.csv
→ response too big; falls into Pattern 4 below
→ instead, use shell to stream
2. jettson_shell_run "curl -sS ... > users.csv"
3. jettson_shell_run "awk -F, '$5 == \"active\"' users.csv > active.csv"
4. jettson_shell_run "wc -l active.csv > stats.txt"
5. jettson_files_read stats.txt
6. Mind composes the email body
7. jettson_http_request POST to your transactional email APISteps 2-3 use the shell because that's where awk lives. Steps 1, 5, 6, 7 use the smaller-footprint tools that hand data back to the Mind. The big file never lands in the Mind's context — only the summary does.
Pattern 3 — Remember across runs
Memory + everything. Memory turns "an agent that does X" into "an agent that does X and gets better at it."
The shape is always the same:
1. jettson_memory_search at the start — recall what you know
2. (do the work, whatever pattern fits)
3. jettson_memory_put at the end — remember what you learnedAuto-extraction handles (3) for the cross-cutting insights. You only need to do explicit puts when you want a specific key shape or a TTL.
Example: "Triage Stripe events."
1. jettson_memory_search for "Stripe triage patterns" + tone preferences
2. jettson_http_request GET https://api.stripe.com/v1/events
3. Mind classifies each event using recalled rules
4. jettson_http_request POST to Slack with the summary
5. For each NEW event type the agent classified: jettson_memory_putAfter 5 runs the agent rarely surfaces a "new" event type; it's mostly drawing from memory.
When to NOT compose
Single-tool tasks exist and they're fine:
- "Send a Slack message" — just
jettson_http_request. No need for memory or browser. - "Read a config file from /workspace and parse it" — just
jettson_files_read. No need for HTTP.
Don't bolt memory onto everything — if there's nothing worth remembering, skip the puts. Auto-extraction is a no-op when the run produced no durably-useful insights.
Anti-patterns
- Browser for things that have an API. Slower, fragiler, and won't scale to a million runs. Always check for a public API first.
- Shell for one-line transforms the Mind could do. If the work is "uppercase this string," let the Mind handle it. Shell is for grep / awk / curl / git — real Linux work.
- HTTP that calls Jettson itself. Refused at the proxy boundary (
.jettson.devdomains are blocked). Use the appropriate memory tool instead. - Files for things you don't need to persist within the run. If the data doesn't outlive a single tool call, just pass it through the Mind's reasoning context.
Related
- Concepts: tools — the broader model
- Each tool's reference — start with browser, then the rest
- Handling failures — what to do when one tool in a chain breaks