Skip to content

feat(plugins): Recipes Pack — durable named playbooks - #31

Merged
rrader26 merged 1 commit into
mainfrom
feat/recipes-pack
May 12, 2026
Merged

feat(plugins): Recipes Pack — durable named playbooks#31
rrader26 merged 1 commit into
mainfrom
feat/recipes-pack

Conversation

@rrader26

Copy link
Copy Markdown
Contributor

Summary

  • New `createRecipesPlugin()` adds 4 tools for saving + retrieving named MCP-tool-call sequences with parameter substitution.
  • The flywheel feature: once the agent learns how to drive a workflow, the sequence becomes a Recipe and never needs to be rediscovered.

Tools

Tool Use
`agentmark_recipe_save` Persist a recipe with parameter schema + ordered steps
`agentmark_recipe_list` List recipes, optionally filter by `target_app`
`agentmark_recipe_get` Fetch a recipe; pass `params` to get the resolved plan
`agentmark_recipe_delete` Remove

Architectural choice: playbooks, not auto-executors

`agentmark_recipe_get` returns a resolved plan (parameter substitutions applied). The AI then dispatches each step itself, in its own reasoning chain. The plugin deliberately does NOT auto-execute server-side.

Three reasons:

  1. No recursive Dispatcher coupling. The recipes plugin needs no reference to the surrounding server.
  2. AI visibility. Each step appears in the model's reasoning chain — better for the model + better for the user reviewing what was done.
  3. Flexible verification. Steps can include `verify` hints describing what the next `agentmark_desktop_diff` should look like, and the agent decides what "verified" means rather than the server enforcing rigid assertions.

Pairs naturally with `agentmark_desktop_diff` from PR #26.

Substitution syntax

`{{param.name}}` in any string arg.

  • Bare token `"{{param.count}}"` preserves the param's native type → `42` (number), `true` (boolean), etc.
  • Embedded `"Hello {{param.name}}, you have {{param.count}} items"` always string-interpolates.

Parameters carry a type schema (`string | number | boolean`), optional defaults, and a `required` flag.

Example

```json
agentmark_recipe_save {
"name": "fill-nowcerts-customer",
"target_app": "nowcerts",
"parameters": [
{ "name": "company_name", "type": "string", "required": true },
{ "name": "phone", "type": "string" }
],
"steps": [
{
"tool": "agentmark_desktop_execute",
"args": { "action_id": "act_in_company", "value": "{{param.company_name}}" },
"verify": { "expect_value_changes": [{ "element_id": "in_company", "to": "{{param.company_name}}" }] }
},
{
"tool": "agentmark_desktop_execute",
"args": { "action_id": "act_in_phone", "value": "{{param.phone}}" }
}
]
}

agentmark_recipe_get {
"name": "fill-nowcerts-customer",
"params": { "company_name": "Globex Corp", "phone": "555-0100" }
}
→ { resolved: true, steps: [...with substitutions applied...] }
```

Storage

Single JSON file at `~/.thinkfleet/agentmark/recipes.json` (mode 0600). Atomic writes via temp-file + rename. Separate from the Foundations `StateStore` so recipes don't bloat the general K/V file and so they can be backed up / synced independently.

Test plan

  • `pnpm build` clean
  • `pnpm test` — 431 pass / 10 skip (24 new: substitution, parameter coercion, store CRUD, durability, dispatcher integration)
  • Manual: record a 5-step NowCerts customer-add flow as a recipe, replay it on a fresh window, verify each step lands via diff

🤖 Generated with Claude Code

Saved sequences of MCP tool calls with parameter substitution. The
flywheel feature: once an agent figures out "to add a customer in
NowCerts, click X then Y then Z", that knowledge becomes a Recipe and
future runs replay the sequence instead of rediscovering it.

Tools shipped (4):
  agentmark_recipe_save     persist a recipe with parameters + steps
  agentmark_recipe_list     list saved recipes (filterable by target_app)
  agentmark_recipe_get      fetch + optionally resolve a recipe
  agentmark_recipe_delete   remove

Recipes are stored as JSON at ~/.thinkfleet/agentmark/recipes.json
(mode 0600), atomically via temp-write + rename. Each save bumps a
monotonic version counter and timestamps. Separate from the Foundations
StateStore so recipes don't bloat the general K/V file.

Substitution syntax: `{{param.name}}` in any string arg.
  - Bare token "{{param.name}}" preserves the param's native type.
  - Embedded "prefix {{param.name}} suffix" string-interpolates.

Parameter schema supports type validation, required flag, defaults.
String-to-number coercion is lossless. Each parameter is typed
(string | number | boolean).

Architectural choice: recipes are **playbooks**, not auto-executors.
agentmark_recipe_get returns a resolved plan; the agent dispatches
each step itself. Three reasons:
  1. No recursive Dispatcher coupling — the recipes plugin needs no
     reference to the surrounding server.
  2. The AI sees each step in its reasoning chain (better for the
     model + better for the user reviewing what was done).
  3. Recipe steps can include `verify` hints describing what the next
     diff should look like, and the agent decides what "verified"
     means rather than the server enforcing rigid assertions.

Pairs naturally with agentmark_desktop_diff (PR #26) for step-by-step
verification during replay.

Tests (24 new, 431 total): substitution semantics (bare/embedded
tokens, recursion into nested structures, strict mode), parameter
schema (defaults, required, coercion), store CRUD (save/get/list/
delete, on_conflict semantics, durability across instances, target_app
filter), dispatcher integration (full save→resolve→get cycle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rrader26
rrader26 merged commit 32451fd into main May 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants