Composing reusable AI workflows

Several of my AI workflows need to do similar things: read a ticket and its requirements, understand the relevant code, check the working environment, load company conventions, plan a change, review its behavior or run the relevant tests. Investigations need to resolve the right environment and correlate evidence. Delivery workflows need to assess feedback, update a PR description and leave enough context for the work to continue later.

Those needs overlap. Implementing a feature and fixing a review comment both need validation after code changes. Reviewing a plan and reviewing a PR can both benefit from an architectural perspective. A RabbitMQ investigation may need the same log-searching workflow that I use directly. Putting all of those instructions into every skill would leave me maintaining several versions of the same procedure.

Instead, I want to compose workflows from smaller parts. A shared review step can support both implementation and a standalone PR review. An agent can bring a particular perspective wherever that perspective is useful. A script can handle a repeatable operation without asking the AI to reconstruct it each time.

My raholsn plugin brings those pieces together. The individual posts in this series describe what each workflow does. This one looks at how they connect, using the plugin's docs/command-dependencies.md as a map of the current design.

Three workflows connected to shared instruction cards, focused role cards and a tray of reusable tools

Give each part a clear job

The implementation described here is a Claude Code plugin. The idea of composing reusable instructions applies more broadly, but command registration, agent configuration and integration files depend on the tool hosting them.

These are the main pieces in my plugin:

PartPurposeExample
User-facing skillCoordinates a task I ask the assistant to performwork, code-review, rabbitmq
Reference skillSupplies a shared procedure or supporting guidanceref-review-loop, ref-build-and-test
AgentHandles a focused assignment with its own role and contextarchitect, functional-reviewer, qa
Profile and company guidanceSupply the context that varies between workplacesTracker settings, engineering conventions
MCP connectionExposes external tools and data to the assistantElastic, Linear, SQL Server
LSP configurationMakes language-server support availableC#, Terraform, YAML
Bundled scriptImplements a repeatable local operationget-deploy-status.sh

The plugin packages the reusable pieces so I can maintain them together. Its current manifest registers 15 commands, alongside 21 internal ref-* skills and eight bundled agents. Those counts describe this version, rather than a target for how large a plugin should become.

What I mean by a reference skill

The ref- prefix is my convention for internal supporting skills. Some describe a procedure, such as validating a change. Others resolve guidance that several agents need, such as the company's testing conventions.

I do not normally invoke these myself. A parent workflow explicitly references the supporting skill when it needs it. That keeps the user-facing command focused on the task while giving the shared instructions a place of their own.

For example, ref-build-and-test describes how to prepare for the selected checks, run them, handle cleanup and report the result. work uses it during implementation. fix-comments can use it after changing code, and the review loop uses it by default to validate fixes.

If I improve how that shared procedure preserves a setup failure while also reporting a cleanup failure, the callers can use the updated procedure. I do not need to find and reconcile separate copies inside each workflow.

In this Claude Code implementation, the reference files use:

user-invocable: false
disable-model-invocation: false

The first hides the skill from the slash-command menu; the second leaves it available to the model. The rule that it should only be used when another workflow references it is expressed in the instructions. These flags alone do not enforce that caller relationship. The skill invocation documentation explains the distinction.

A skill can delegate to an agent

A reference skill and an agent have different responsibilities. The reference describes how a step fits into the workflow: what input it needs, who should do the work and what result the caller expects. The agent carries out the focused assignment.

For example, ref-architect-review passes the task brief and relevant source or diff to the architect agent. The agent examines boundaries, contracts, concurrency and failure behavior, then writes architectural feedback. The calling workflow decides how to apply that feedback.

The same architecture perspective can be useful before implementation or while reviewing an existing PR. What changes is the supplied task and evidence.

The functional reviewer has a different focus: whether the change delivers the intended behavior and user journey. QA examines the evidence that it works. Keeping those roles explicit helps the caller choose the perspectives that matter, then reconcile overlapping findings.

Agents also need shared context. Several of mine preload ref-company-conventions and ref-company-testing through their skills frontmatter. I configure the current company’s guidance directly in those shared references. That is context supplied to the agent, rather than another agent being launched. Claude Code documents these preloads in its subagent configuration reference.

Reuse the review step in two different workflows

The review loop is a useful example of composition because its callers need different behavior.

During implementation, work can ask for a review, address supported findings, validate the fixes and review again when the changes warrant it. A standalone code-review request needs findings about the supplied PR; it should not begin modifying that change as part of the review.

Both use ref-review-loop, with an explicit mode:

CallerModeResult
workloopReview, address findings, validate changes and repeat when useful
code-reviewsingle-passReview once and return findings

The reference also accepts the reviewer, feedback-file path, diff source and validation call. Its defaults are the functional reviewer and the shared build-and-test procedure.

That makes the common procedure reusable while leaving the caller in control of the task. The input matters: a saved PR diff must not be replaced by whatever happens to be in the local working tree.

This simplified diagram shows those relationships. Arrows identify dependencies, not the order of every action in a run.

Work and code review share a review procedure, which delegates to a functional reviewer and uses validation after loop-mode fixes

Open the review example at full size

Shared artifacts make the handoff concrete. A task brief records the scope and requirements, the reviewer produces feedback in an agreed location, and the caller knows where to find it. Reuse depends on that agreement about inputs and outputs as much as it depends on shared wording.

Commands can compose other commands too

Composition does not always need a reference skill or an agent. The RabbitMQ workflow resolves its connection through profile and can call logs when it has relevant identifiers and a configured log connection.

That lets the RabbitMQ skill concentrate on broker evidence while the logs skill owns the log investigation. Improvements to log querying and correlation can be reused without copying that method into the broker workflow.

Some relationships are simply handoffs between tasks. The planning sequence is:

grill-me-pragmatic → write-requirements → plan-implementation → work

I choose when to move between those stages. Producing a requirements document does not automatically run issue planning or start implementation. That is why the dependency guide distinguishes a suggested workflow sequence from an actual instruction to invoke another skill.

The tools folder handles repeatable operations

The plugin also contains shell scripts under tools/. Four small commands directly invoke matching scripts for deployment status, opening a PR-related page, opening a solution and opening an Argo CD application.

For example, get-deploy-status resolves the repository, workflow and job filter, then passes them to get-deploy-status.sh. The script reads GitHub Actions results and returns statuses and links. It does not establish live application health.

The split is useful: the skill interprets the request and resolves the arguments; the script performs the defined operation and reports its result. If the script's argument contract stays the same, I can change its implementation without rewriting how the skill understands the request.

These small commands do not need the whole work workflow or profile setup. There is also a create-branch-and-pr.sh helper for the combined operation supported by its reference skill. Its presence in the plugin does not mean every workflow runs it: work uses that reference for naming guidance without invoking the combined helper.

MCP and LSP provide capabilities

The current .mcp.json declares connections for Elastic, Linear and SQL Server. These expose capabilities that workflows can use: querying logs, reading tracker context or accessing the configured database tools.

A connection still needs the appropriate endpoint, authentication and permissions. Declaring it in the plugin does not establish access. The workflow decides which available tools are relevant to the request and what to do with their results.

The .lsp.json file configures language servers for C#, Terraform and YAML. I do not use that part much yet, but I like having language-server support available when it is useful for code navigation or diagnostics. The host and installed server determine which operations are available; I am not claiming every workflow currently uses them.

This setup still has practical portability work left. The current C# configuration contains machine-specific paths, and the configured language-server binaries need to be installed. Packaging the configuration is only part of making it usable elsewhere. The Claude Code plugin reference describes the MCP and LSP integration points.

Keep workplace context separate

In Making skills useful across workplaces, I described using a profile and optional company pack for settings and guidance that change between companies.

That separation also helps composition inside the plugin. The architect, planner and functional reviewer all use the same company reference skills. I configure conventions and testing guidance directly in those references for the current assignment, keeping their names stable when moving to the next company. The agents do not need their own copies of that guidance.

If a company updates its testing guidance, I update the shared testing reference. An external document can still be selected when useful, but a separate pack is optional. If I improve how a review is coordinated, the change belongs in the workflow. If a connection moves, its configuration changes. Giving those changes different homes makes it easier to see what needs updating and which callers may be affected.

Use the dependency map when changing shared behavior

The full chart below is copied from docs/command-dependencies.md. It shows commands, references, agents and bundled script dependencies in the current source. It is a maintenance map, not a record of which steps ran during a particular task.

Explore the full plugin dependency map

Arrows point from callers to their dependencies. Thick arrows connect commands; solid arrows show reference use or agent delegation. Dashed agent arrows show preloaded context, and the naming-only reference from work is explicitly labelled. Conditional labels explain when a relationship applies. Configured domain reviewers sit outside the fixed set of bundled agents.

The chart is large; open the full-size version to inspect individual connections.

Full source dependency map of the raholsn plugin's commands, reference skills, agents and bundled script commands

Open the full dependency map

Download the Mermaid source

Centralizing a procedure also means a change can affect several workflows. Updating the default validation in the review loop deserves a check of its callers, especially the difference between loop mode and single-pass review. Changing a feedback format means checking both the agent that writes it and the caller that reads it.

I want the graph to make those dependencies visible. It needs updating when the source relationships change; a diagram that drifts away from the instructions can be misleading.

There is a balance to the decomposition too. A separate reference is useful when it has a clear responsibility and meaningful reuse. Splitting every paragraph into another file would make the workflow harder to follow. Shared instructions reduce duplication, but they still need clear boundaries and validation in the workflows that use them.

The plugin and dependency guide

You can find my plugin and the command dependency guide on GitHub.

This post describes the local plugin structure as of its updated date. The diagram reflects source relationships; it does not establish that every integration or workflow has been exercised live.

For me, the benefit is being able to improve a shared piece and use it in several places, while keeping each workflow understandable. Skills describe the method, agents contribute focused work, and tools provide the operations. Composing them gives me more useful workflows with fewer copies of the same instructions to maintain.

Happy coding!

Please share
𝕏finLINEtIw