feat: operation-focused skills + ops bundling on get_workflow / get_activity#110
Open
feat: operation-focused skills + ops bundling on get_workflow / get_activity#110
Conversation
…ps bundling Schema additions (dual-support — legacy fields stay valid): - activity.skill_operations[]: flat array of skill-id::op-name refs. - step.operation + step.args: per-step operation reference + args. - workflow.skill_operations[]: workflow-level operation refs (for the orchestrator-scope bundle returned by get_workflow). - skill.operations[].procedure / output / tools / prose: formalize the operation body so simple linear procedures, output specs, inline tool refs, and reference prose all have a home. Loader and tools: - New resolveOperations(refs[]) function in skill-loader.ts. Parses skill-id::element refs (with optional workflow prefix), looks up each across the skill files, and returns annotated entries. Auto-includes a touched skill's global rules in the result so any activity referencing one operation from a skill also gets that skill's invariants. - New resolve_operations MCP tool (no session token) that returns the resolved bundle as TOON. - src/loaders/core-ops.ts declares CORE_ORCHESTRATOR_OPS and CORE_WORKER_OPS — the baseline operations every orchestrator/worker needs (engine traversal, checkpoint flow, persistence). These are bundled into get_workflow and get_activity responses respectively. - get_workflow now embeds (workflow.skill_operations + core ops) ahead of the workflow body, separated by '\n\n---\n\n'. Legacy primary- skill body still included before the bundle when present. - get_activity now embeds (activity.skill_operations + core worker ops) ahead of the activity body with the same separator. - get_skills marked DEPRECATED in description; retained for backwards-compatibility during the migration window. Tests updated: transitionToActivity helper and get_activity-shape assertions parse the post-separator section. All 269 existing tests pass with dual-support intact (legacy workflows on skills.primary continue to load). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Operation `tools` field schema (both Zod and JSON Schema) becomes `Record<source, string[]>` — source key is an MCP server name (workflow-server, atlassian, gitnexus, concept-rag, ...) or one of the reserved keys 'shell' / 'harness'. Provenance hint only — tool specs come from the tool descriptions themselves. - Test updates aligned with the meta workflow's migration to skill_operations: get_skill / get_skills tests that previously asserted meta primary-skill behaviour now use work-package (still on legacy skills.primary) or assert no-body behaviour for migrated workflows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
… resource refs - Rename activity.skill_operations → activity.operations and workflow.skill_operations → workflow.operations (symmetric with skill.operations). - Add per-operation resources: array on OperationDefinition; the auto-include path in resolveOperations now treats per-op resources as scoped to operations actually requested. Top-level skill.resources stays optional for legacy use. - Resource loader: support id-based refs (e.g., "meta/workflow-state-format") in addition to numeric indices. resolveResourceRefToIndex parses each candidate file's frontmatter to find an id match; numeric refs pass through unchanged. - core-ops.ts: rename references state-management::* and session-protocol::* to workflow-engine::* (those skills are merged into workflow-engine on the workflows branch). - WorkflowSkillsSchema.primary becomes optional — workflows that have migrated drop the skills block entirely. - Test updates aligned with the migration: get_skill / get_skills tests assert the new no-primary behaviour for migrated workflows; one test reframed to check the resolved-operations bundle in the get_workflow preamble; legacy primary-body assertions skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…resence discover-session has migrated off skills.primary. Its operations[] block is now omitted entirely — the activity relies on the core worker operations bundled by get_activity. Update the activity-loader sanity test to assert the skills block is absent rather than checking that operations[] is defined. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ssion, deprecate operation/args fields
Activity step schema changes:
- name becomes optional (was required); steps are identified by id and described inline.
- when: string field added — inline boolean expression that gates step execution (e.g., "has_saved_state == true"). Evaluated against current variable state.
- operation and args fields removed — operation invocation now lives inline in the description as `skill-id::operation-name(arg: {var})`.
- condition (structured ConditionSchema) retained as legacy alternative.
- skill / skill_args retained as legacy.
Step contract simplifies to: { id, description, when?, condition? } — id identifies, description carries the inline invocation, when gates execution.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add an `errors` field to OperationDefinitionSchema mirroring the existing resources scoping. Errors live on the operations they pertain to and travel with the operation body when resolved via get_workflow / get_activity / resolve_operations. Top-level skill.errors stays optional for legacy skills. skill-loader.test.ts updated: - "should load workflow-engine skill with operations and rules" asserts that at least one operation declares per-op errors. - "should have per-operation error recovery patterns" walks every operation's errors map and validates cause + recovery fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a `rules` field to OperationDefinitionSchema so role-specific rules can live on the operations they constrain rather than at the skill top-level. Same shape as skill.rules (RulesDefinitionSchema). Motivation: when resolveOperations auto-includes a touched skill's rules, top-level rules leak across role boundaries — a worker that requests a worker-only operation from workflow-engine would also receive orchestrator-only rules. Per-operation scoping eliminates that leak; only the operation's own rules travel with it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The harness field carved a special-case slot for harness-compat-style operations. After harness-compat moved per-harness mappings into each operation's `prose` (a small markdown table), the discrete `harness` field has no remaining users. Removed: - OperationDefinition.harness (Zod + JSON schema) - OperationHarnessSchema export Operations now follow a single uniform shape: description, inputs, output, procedure, tools, resources, errors, rules, prose, note. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reflect schema and tool changes since ff77d93 (operation-focused refactor): bundled operations in get_workflow / get_activity, the new resolve_operations tool, dropped harness field, inline step operation invocations, removed modeOverrides claim, and current src/loaders layout (core-ops.ts, no rules-loader.ts). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pick up design review artifacts for the work-package workflow (2026-04-26 review session). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…an up stale resource references - workflows submodule: agent-managed persistence, removed obsolete resources - docs: update resource_resolution_model examples from meta/03 to id-based refs Made-with: Cursor
work-package: add reconcile-assumptions and classify-problem skills Made-with: Cursor
work-package: move step-level skill refs to activity-level supporting blocks Made-with: Cursor
CORE_ORCHESTRATOR_OPS shipped dispatch-activity (whose body ends with "harness-compat::spawn-agent with the composed prompt; await result") without the harness-compat operations themselves. resolveOperations doesn't recursively follow operation references inside bodies, so any client workflow that doesn't redeclare harness-compat at the workflow level (e.g., work-package, which has no `operations` field) sent its orchestrator into dispatch with an instruction to call spawn-agent and no harness-specific prose for what spawn-agent actually maps to. The orchestrator improvised — generally fine on fresh start, but on resume it biased toward inlining activity execution. Adding spawn-agent and continue-agent to the core orchestrator bundle guarantees every orchestrator receives the cursor/cline/generic implementation table, restoring deterministic dispatch. Also bumps the workflows submodule pointer for the matching checkpoint-resume token-threading fix and the no-inline-on-resume discipline rule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…efactor
11 tests were failing on this branch because they exercised
get_skill({ step_id }) — the per-step skill resolution path. Workflow
content has fully migrated to operation-focused (activity.skills.supporting
+ inline skill::operation invocations in step descriptions); no real
activity declares step.skill anymore, so the tests asserted against
fixture data that no longer exists. Server still supports the legacy
code path for backward compatibility, but it is no longer covered by
real workflows.
Drops the 4 tests that exist solely to cover get_skill({ step_id })
behaviour and the 7 lifecycle/inheritance/checkpoint tests that happened
to use it as a stand-in tool call. Sibling tests still cover get_skill's
error paths (missing step, no primary skill, no activity in token).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up 8e219e4 (chore: switch submodule URLs to SSH). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Group the bundle by kind at the response boundary so per-entry redundancy drops out of get_workflow / get_activity / resolve_operations payloads: operations and errors become objects keyed by <skill>::<name>; rules flatten to [header, line] tuples; unresolved refs collect into a string array. The per-entry workflow, type, and ref fields are folded away. Resolver shape (ResolvedOperation) is untouched — formatting happens at the tool boundary so resolveOperations stays testable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two failure modes were observed in resumed workflows: - Orchestrators sent step_manifest as "" (string) instead of []. - Orchestrators sent entries keyed by id instead of step_id, matching the activity TOON shape (steps[].id) rather than the manifest schema. Tighten the Zod .describe() to spell out the array shape, give a concrete example, call out that the field is step_id (not id), and state that the parameter should be omitted — not stubbed with [] or "" — when no steps ran. Bumps the workflows submodule for the matching engine-rule update. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…paths start_session was passing effectiveWorkflowVersion='' to createSessionToken on both fresh-session paths (recovery from corrupt token, and brand-new session). The token's v field stayed empty, which forced saved state files to redundantly carry workflowVersion at the envelope level just so resume could read it back. Both fresh paths now loadWorkflow before createSessionToken and pass the workflow's version through. Inherit and re-sign paths already preserve v from the existing payload, so they were already fine. Bumps workflows submodule for the matching slim workflow-state.json shape (94e5e9e). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in 024288b: changes/ fragment must reference the GitHub issue (uses captured issue_number/issue_url/issue_platform variables). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in 25b80b9: post-activity commit invariant consolidated in workflow-engine; commit-and-persist now covers both source-side (target_path submodule) and engineering artifact commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…oundary start_session was registered via server.tool(name, desc, rawShape, cb), which the MCP SDK wraps in a default z.object() (.strip()-mode). That silently dropped unknown parameter keys before the handler ever saw them. An orchestrator that mistakenly passed a saved client token under a 'saved_session_token' key (a workflow-engine VARIABLE name, not an MCP PARAMETER name) had its key dropped, no error raised, and the server took the fresh-session-with-parent branch instead of the adoption branch. The saved state was abandoned, and a downstream next_activity call later failed with HMAC verification because the agent kept passing the literal saved token. Convert the registration to server.registerTool with inputSchema: z.object(shape).strict() so unknown keys fail loudly with Input validation error: ... unrecognized_keys. The handler signature is unchanged. Description text additions: - An explicit STRICT PARAMETERS notice naming saved_session_token as a common mistake (since that's a workflow variable name, not a tool parameter) and pointing the agent at session_token as the correct parameter for resume. - An explicit STALENESS RECOVERY POLICY clause stating that HMAC re-signing is performed ONLY by start_session — no other workflow tool has a recovery path. This pairs with the meta workflow-engine rules introduced in the workflows submodule (c53f28f) and removes any implicit expectation that next_activity etc. might recover. Submodule pointer also bumped to pick up the meta-skill rewrite (workflows c53f28f). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up the eleven workflow-execution friction-point fixes plus the agent-conduct rule-count repair from workflows@373a4b3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up the workflows submodule removal from .engineering@95eebe4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Server-side foundation for operation-focused skills. Activities (and workflows) now declare a flat
skill_operations[]array ofskill-id::operation-namereferences; each step can carry anoperation+argsreference instead of (or alongside) the legacyskill+skill_args. Capability skills expose named operations (description, inputs, output, procedure, tools, prose) addressable by the canonicalskill::namesyntax.get_workflowandget_activitynow bundle the resolved operations into their responses, ahead of a\n\n---\n\nseparator. The bundle is the union of (declaredskill_operations+ core orchestrator/worker ops fromsrc/loaders/core-ops.ts) plus auto-included global rules from any touched skill. Legacy fields (skills.primary,step.skill,step.skill_args) remain valid for dual-support during the migration window.get_skillsis marked DEPRECATED.The companion meta refactor lives on the
feat/operation-focused-skills-metabranch on the orphanworkflowsref — that branch holds theworkflow-enginecapability skill and the migrated activities. This PR delivers the schema + tool surface + dual-support runtime that the meta refactor depends on.Key changes
Schemas (Zod + JSON):
activity.skill_operations[],step.operation,step.argsadded (all optional).workflow.skill_operations[]added (optional).skill.operations[*]formalized:description,inputs,output,procedure,tools(source-keyed map → array of tool names),prose,harness,note.step.skill/step.skill_argsandactivity.skillsretained for legacy.Loader:
src/loaders/skill-loader.tsaddsresolveOperations(refs[])— parsesskill::elementrefs (with optional workflow prefix), looks up across skill files, and returns annotated entries. Auto-includes a touched skill's global rules in the result.Tools:
resolve_operations(no session token) — public access to the operation-resolution primitive.get_workflowandget_activityembed the resolved-operations bundle ahead of the workflow/activity body, separated by\n\n---\n\n.get_skillscarries a deprecation note.Core ops registry:
src/loaders/core-ops.tsdeclaresCORE_ORCHESTRATOR_OPSandCORE_WORKER_OPS— the baseline operations every orchestrator/worker needs.Test plan
npm run typechecknpm test— 269 / 269 pass with dual-support intact (legacy workflows unchanged).feat/operation-focused-skills-metaPR on the workflows branch — meta workflow loads, operations bundle correctly, activities run withskill_operations+step.operation.🤖 Generated with Claude Code