Materialization Plans

Materialization turns a capability graph into runnable artifacts. Webcmd uses a two-step flow: prepare a packet from graph context, then apply an agent-authored plan that matches the packet schema.

flowchart LR; Graph["capability graph"] --> Packet["materialization packet"]; Packet --> Plan["plan JSON"]; Plan --> Validate["schema and graph validation"]; Validate --> Workflow["workflow script"]; Validate --> GeneratedCLI["generated CLI"]; Workflow --> Verify["webcmd verify"]; GeneratedCLI --> Verify;

Workflow materialization

webcmd workflow <app-id> --task "Collect top stories"
# writes .webcmd/graphs/<app-id>/workflow.packet.json

webcmd workflow <app-id> --plan .webcmd/graphs/<app-id>/workflow.plan.json
# writes .webcmd/exports/workflows/<domain>/<workflow-id>.mjs

Workflow plan schema:

{
  "workflowId": "top-stories",
  "uses": [
    { "capability": "hacker_news.list_top_stories", "with": { "limit": "$limit" } }
  ],
  "params": {
    "limit": {
      "type": "number",
      "required": false,
      "description": "Maximum number of stories to return"
    }
  },
  "script": "complete executable ESM source"
}

Constraints:

FieldRule
workflowIdSingle path segment; no /, \, ., or ...
usesAt least one known graph capability.
paramsOptional record of typed workflow args: string, number, boolean, json.
scriptComplete .mjs workflow source.

The script must export workflow = { version: 1, id, task, params, output? } and run(input, options). It should import only createWorkflowRuntime and parseWorkflowArgs from webcmd/runtime, use public runtime methods, honor auth summary, close the runtime, and avoid importing graph/session sidecar files at runtime.

CLI materialization

webcmd cli <app-id> --task "Create a jobs CLI"
# writes .webcmd/graphs/<app-id>/cli.packet.json

webcmd cli <app-id> --plan .webcmd/graphs/<app-id>/cli.plan.json
webcmd cli <app-id> --plan .webcmd/graphs/<app-id>/cli.plan.json --install-skill
webcmd cli <app-id> --plan .webcmd/graphs/<app-id>/cli.plan.json --export skill --force

CLI plans are discriminated by mode.

Create plan

{
  "mode": "create",
  "commands": [
    {
      "name": "search",
      "description": "Search jobs by keyword",
      "uses": ["linkedin.search_jobs"],
      "localCode": ["src/index.mjs"],
      "smokeTest": {
        "args": ["search", "--help"],
        "expect": "Search jobs"
      }
    }
  ],
  "files": {
    "package.json": "{ ... }",
    "src/index.mjs": "..."
  }
}

files must not be empty. File paths must stay inside the generated package, target files rather than the package root, avoid absolute paths, avoid .., and pass package path validation.

Update plan

{
  "mode": "update",
  "intent": "add-command",
  "commands": [
    {
      "name": "saved",
      "description": "List saved jobs",
      "uses": ["linkedin.list_saved_jobs"],
      "localCode": ["src/index.mjs"],
      "smokeTest": {
        "args": ["saved", "--help"],
        "expect": "saved"
      }
    }
  ],
  "edits": [
    {
      "path": "src/index.mjs",
      "operation": "replace",
      "content": "..."
    }
  ],
  "remove": []
}

intent must be add-command, modify-command, remove-command, or refresh-docs. edits must contain at least one write/replace operation. If the plan edits SKILL.md or changes command metadata, commands is required.

CLI command contracts

FieldMeaning
nameGenerated command name.
descriptionHuman/agent readable command summary.
usesCapability ids used by this command; every id must exist in the graph.
localCodeGenerated package files that implement the command.
smokeTest.argsSafe validation args; must include --help, --dry-run, or --validate.
smokeTest.expectOutput text expected from the smoke test.

Auth-aware workflow implementation

Materialization packets include authSummary. Use it before choosing the runtime pattern:

Capability authWorkflow pattern
Public-onlycreateWorkflowRuntime(options).
browser-cookie or browser-requestcreateWorkflowRuntime({ ...options, auth: true }); use browser context/http as appropriate.
page-fetchInitialize with auth when profile is required, navigate to an allowed app origin, then runtime.pageFetch({ ..., allowedOrigins }).
interceptUse runtime.waitForResponse(matcher, action) with a narrow graph-approved matcher and minimal UI trigger.
manual or unsupportedDo not invent hidden HTTP or credential extraction; report the unsupported path unless UI replay is enough.

Verification

webcmd verify .webcmd/exports/workflows/<domain>/<workflow-id>.mjs
webcmd verify .webcmd/exports/clis/<domain>

Workflow verification loads the script and runs it with an injected fake runtime. Generated CLI verification validates package structure and metadata. Neither path uses real credentials.