Profile-driven ADLC workflow tooling for turning approved RHAI feature requests
into reviewed, published strategy artifacts. It implements the workflow proposed
in proposals/013-fullsend-strat-workflow/proposal.md, with runtime state kept
private to tooling and publishable artifacts kept under the profile-defined
artifact layout.
The workflow deliberately supports three ways to run the same profile and task protocol. This is a core project feature, not transitional compatibility code. Different teams have different, reasonable perspectives on how agentic work should be controlled: an agent can own the whole run, an agent can hand work to a deterministic harness, or a harness can be invoked directly. ADLC keeps those choices comparable so evidence—not an assumed architecture—can determine which method is best for a workflow.
| Mode | Entry point | Control boundary | Useful when |
|---|---|---|---|
| Agent-led | claude -p "/adlc-workflow:adlc-workflow RHAIRFE-1" |
The outer Claude session drives the workflow, skills, and protocol tools. | Exploring the workflow, using adaptive judgment, or retaining the full native Claude session trace. |
| Skill → CLI handoff | claude -p "/adlc-workflow:adlc-workflow --handoff --profile=rhai-feature-creator RHAIRFE-1" |
The outer skill performs one delegation to the deterministic controller, which launches bounded workers. | Keeping a Claude-facing entry point while making scheduling, retries, parallelism, state, and artifact handling deterministic. |
| Direct CLI | adlc-workflow handoff --profile rhai-feature-creator RHAIRFE-1 |
The deterministic controller owns the run directly and launches Claude only for bounded LLM tasks. | Automation, batch execution, parallel item processing, structured observability, and minimal outer-agent context use. |
All three modes use the same profile, core task/result contract, context preparation, private state, artifact layout, publication adapters, and bounded worker definitions. They differ only in who controls the workflow loop. The controller modes retain normalized event streams and raw worker transcripts; agent-led mode retains Claude's native stream. Evaluate modes on artifact quality, reliability, cost, latency, observability, and operator fit before standardizing on one.
A batch is one run with a frozen set of selected tickets, per-ticket tasks and
artifacts, and a publication barrier after all selected tickets finish processing.
The controller accepts explicit issue keys or discovers eligible tickets from the
profile's initial gate. Discovery applies eligibility checks before
--batch-offset and --batch-size; explicit keys preserve their supplied order
after deduplication.
Batch size and concurrency are separate controls:
- Agent-led: processes tickets and their reviewers serially, warning that reviewer parallelism is not enforced in this mode.
- Skill → CLI handoff and direct CLI: process tickets serially by default;
--item-parallelism Nallows up to N processing tasks across tickets at once. Each ticket can advance from refinement to review independently—there is no batch-wide refinement barrier. - Reviewer concurrency: controlled separately by the profile for each review task. Concurrent tickets can each fan out reviewers, so item parallelism is not a global limit on model subprocesses.
For example, discover up to ten eligible tickets and process up to two tasks concurrently:
adlc-workflow handoff --profile rhai-feature-creator --workspace /workspace \
--batch-size 10 --item-parallelism 2A failed processing task prevents normal batch publication; completed artifacts remain available for inspection. See Batch selection and execution for selection rules, serial/concurrent execution diagrams, reviewer fan-out, and failure boundaries.
src/adlc_workflow/— deterministic lifecycle, task protocol, state, and effect coordination.skills/andagents/— agent-facing interfaces and runtime definitions.plugins/— versioned concern packages with manifests, prompts, schemas, and fixtures.config/,policies/, andschemas/— reviewed configuration and contracts.adapters/— production, local-emulator, and evaluation boundaries.artifacts/— the shared result-bundle layout.scripts/— launch and trusted validation entrypoints.tests/— contract, integration, and Fullsend acceptance-test locations.
See the proposal for the ownership, lifecycle, and acceptance requirements.
The feature profile declares five agent: reviewers. In agent-led mode, the
review dispatch skill launches native Task/Agent calls serially; in controller
modes, reviewer subprocesses can run concurrently according to the profile.
Individual reviewers no longer use forked Skill calls. The
adlc-review-plan helper supplies profile-selected paths and agent assignments.
Dispatch waits for all agents to succeed and checks their output files before
aggregation.
To test native reviewer concurrency without resetting Jira or running the whole workflow, run this inside the configured Claude container:
podman-compose exec claude python3 \
/home/evaluator/.claude/plugins/adlc-workflow/scripts/test-reviewer-concurrency.pyThis makes a live model call (budget cap $1) using isolated temporary fixture
documents and a fixture rubric. It retains the JSONL log and asserts that all
five reviewer executions start before the first completion, all succeed, and
all output files exist. It tests native agent dispatch; a full workflow run
is still needed to check the parent skill's orchestration and aggregation.
The production config/rubrics/rhai-feature-review.yaml is a pinned,
repository-local copy of the approved four-dimension strategy rubric.
The end-to-end test starts the local checkouts/jctanner/jira-emulator
checkout, creates RHAIRFE-1, copies this project into a temporary runtime
workspace, and mounts the source at /tmp/adlc-workflow. The container copies
that mount into /home/evaluator/.claude/plugins/adlc-workflow and invokes the
installed plugin from /workspace.
Build the shared agent image when the launcher image is not already present:
podman build -t adlc-claude-task-runner:local -f adlc-workflow/Dockerfile.claude adlc-workflowThen run the opt-in test with Vertex settings exported, or with the supported
values available in ~/bin/claude.vertex:
export ADLC_RUN_LIVE_AGENT=1
make -C adlc-workflow integrationThe test mounts Google ADC read-only and never prints its contents. Override
ADLC_AGENT_IMAGE or ADLC_CLAUDE_MODEL when using a different image/model.
Set ADLC_INTEGRATION_CONTROLLER=handoff to exercise the Python handoff
controller through the same plugin entrypoint; its timeout is increased for
the child worker subprocesses.
For a repeatable two-container run, use podman-compose.yaml:
cd adlc-workflow
cp .env.example .env
$EDITOR .env
podman-compose -f podman-compose.yaml up --build --abort-on-container-exitThe Claude service stays running idle so it can be inspected interactively. In another terminal, invoke the workflow with:
podman-compose exec -T claude claude --dangerously-skip-permissions \
--model "$ADLC_CLAUDE_MODEL" \
-p "/adlc-workflow:adlc-workflow $ADLC_ISSUE_KEY"The compose entrypoint registers the direct mount before the container becomes
idle, so claude plugin list should show
adlc-workflow@adlc-local as enabled. --plugin-dir is only needed when
running Claude outside this compose stack.
The plugin mount provides
/home/evaluator/.claude/plugins/adlc-workflow/scripts/run-example-workflow.sh.
It seeds an example RFE, invokes the workflow for the newly returned issue key,
and tees combined Claude output to /workspace/adlc-workflow-run.log:
podman-compose exec -T claude \
/home/evaluator/.claude/plugins/adlc-workflow/scripts/run-example-workflow.sh
podman-compose exec claude tail -f /workspace/adlc-workflow-run.logSet ADLC_CONTROLLER_MODE=handoff to run the same example through the Python
controller via the outer /adlc-workflow skill. The skill delegates once to
adlc-workflow handoff and reports its terminal result. Set it to cli to
invoke that deterministic controller directly, without an outer Claude
session. ADLC_HANDOFF_DANGEROUSLY_SKIP_PERMISSIONS=1 is the explicit
local-container policy that lets child workers write their assigned runtime
artifacts. The default claude value is the agent-led mode.
In cli mode, set ADLC_CONTROLLER_JSON=1 for a live normalized JSONL stream
on stdout. It includes deterministic controller events and tagged raw Claude
worker stream events; a private copy is retained at
.adlc/state/runs/<run-id>/events.jsonl. Without it, the same events are
rendered for humans.
In cli and handoff modes, batch items remain sequential by default.
Set ADLC_ITEM_PARALLELISM=2 to process up to two tasks across tickets
concurrently; each ticket still honors the
profile's reviewer parallelism, and publication remains a barrier after all
selected tickets finish.
The controller can also be invoked without an outer Claude process when the plugin install is available:
/home/evaluator/.claude/plugins/adlc-workflow/scripts/adlc-workflow handoff \
--workspace /workspace \
--profile rhai-feature-creator \
--item-parallelism 2 \
--dangerously-skip-permissions \
RHAIRFE-1Or open a shell inside the agent container:
podman-compose exec claude bashFrom the repository root, pass the environment file explicitly:
podman-compose --env-file adlc-workflow/.env \
-f adlc-workflow/podman-compose.yaml up --build --abort-on-container-exitThe local .env file is gitignored; .env.example is the committed template.
Compose loads .env automatically for interpolation, including
ANTHROPIC_VERTEX_PROJECT_ID.
The ADLC workflow skills use the checked-in commands in scripts/ for Jira
fetches, request creation, task advancement, result-envelope construction, and
submission. Worker skills should write only the substantive markdown; they
should not generate inline Python or heredoc commands for protocol operations.
The claude service receives ADLC_JIRA_URL=http://jira-emulator:8080,
ADLC_JIRA_TOKEN, JIRA_TOKEN, and the read-only ADC mount. The emulator is
started in strict authentication mode by default and shares the configured
token with the agent. Set JIRA_TOKEN, JIRA_USER, ADLC_ISSUE_KEY, or
ADLC_CLAUDE_MODEL to override the local defaults. Set
ADLC_HOST_ADC_PATH if the ADC file is not at
$HOME/.config/gcloud/application_default_credentials.json.
Seed the emulator with the example RFE about an RHOAI MCP server registry:
./scripts/seed-example-rfe.shThe helper uses http://127.0.0.1:8080 by default and applies both
rfe-creator-rubric-pass and strat-creator-3.6. From inside the Claude
container, its compose-provided ADLC_JIRA_URL automatically points at
http://jira-emulator:8080 instead.
The compose service mounts the project directly at
/home/evaluator/.claude/plugins/adlc-workflow. On startup it uses Claude's
normal local-marketplace commands to register and enable the plugin. Because
the marketplace entry uses a command source in link mode, Claude loads the
direct mount in place rather than copying it to the versioned cache. The
runtime workspace is bind-mounted from ./workspace by default; override it
with ADLC_WORKSPACE_DIR when needed.
The workspace bind mount contains only runtime requests, artifacts, and private
state; immutable code and configuration remain in the plugin mount. Jira data
remains in a named volume. Remove the Jira volume when you want a fresh Jira
database:
podman-compose -f adlc-workflow/podman-compose.yaml down -v