Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .claude/skills/builder-agent/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,72 @@ The memory file is what makes it possible to pick up a use-case after weeks with

---

## Pending Integration Pattern

Use this pattern when the solution design includes `⚠ Stub` integrations — adapters that are required but not yet installed on the platform, or whose connection details (hostname, auth method, credentials) are still being confirmed by the customer.

**Goal:** deliver a fully buildable, testable project now. The customer sees real workflows and real progress. When the adapter arrives, swapping in the real task is a single targeted update.

### Stub Workflow (`stub-{integration-name}`)

Build one stub workflow per pending integration. It exercises one core connectivity action — enough to prove the integration wires up correctly end-to-end when the adapter is provisioned.

**Structure:**
```
workflow_start
→ buildPayload (newVariable — assembles minimum input for the core action)
→ callIntegration (newVariable placeholder — sets {integrationName}Status = "pending_adapter")
↓ error
→ workflow_end
workflow_end
```

**Rules:**
- `buildPayload` — `newVariable` task. Assembles the minimum required input per the `integration-model-{name}.json` (e.g., for Slack: `{channel, text}`). No adapter dependency — always runnable without a real adapter.
- `callIntegration` — `newVariable` placeholder. Sets `{integrationName}Status = "pending_adapter"`. Use the hex task ID that the real adapter task will occupy. Error transition pre-wired to `workflow_end`.
- One input variable: `dryRun` (boolean, default `true`). Stub ignores it; activated workflow can use it to skip side effects during testing.
- Add all stub workflows to the same project as the main delivery workflows.

**Choosing the core action:**
- Prefer the simplest write/action that validates auth end-to-end (post a message, launch a job, write a secret)
- If the integration is read-only in this use case, use a lightweight read (get current user, health check)
- Derive the request payload from `integration-model-{name}.json` — that file is the contract

### Placeholder Task (in any workflow)

When a workflow needs to call an adapter that isn't installed, replace the real adapter task with a `newVariable` placeholder — same position, same task ID, same transitions:

1. Use a `newVariable` task in the exact slot the real adapter task will occupy
2. Assign the same hex task ID the real task will use when activated
3. Set variable: `{integrationName}Status = "pending_adapter"` — machine-readable pending state
4. Wire all transitions identically (including the error transition) to how the real task will be wired

### As-Built: Activate Integration Section

For every pending integration, include a dedicated section in `as-built.md`:

```markdown
## Activate: {Integration Name}

When the {AdapterType} adapter is provisioned:

1. Confirm adapter instance name:
jq '.results[] | select(.package_id | test("{name}";"i")) | {id,state}' adapters.json

2. Replace task `{taskId}` in workflow `{workflowId}` with:
(complete replacement task JSON — all fields pre-filled from integration-model-{name}.json,
app and locationType set to the adapter type name, incoming variables wired from the workflow)
Only field left blank: `adapter_id` — fill from step 1.

3. Verify exact field names from the live schema before activating:
POST /automation-studio/multipleTaskDetails?dereferenceSchemas=true
body: {"tasks": [{"name": "{taskName}", "app": "{appType}"}]}
```

This pattern works for both standard Itential adapters (EmailOpensource, Slack) and custom OpenAPI virtual integrations. The `integration-model-{name}.json` file is the contract in both cases.

---

## Guides

### Guide 1: Build a workflow end-to-end
Expand Down
5 changes: 4 additions & 1 deletion .claude/skills/qa-agent/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ Read `customer-spec.md` Section 9 (Acceptance Criteria) and `solution-design.md`

**Not every criterion needs a live job.** Some are checked by inspecting an artifact already produced by another test case (`artifact-inspection`), and some genuinely can't be automated (e.g., "port link status is reported — automation can't fix physical layer" is a statement of scope, not a testable claim) — note those as `not-testable` with a one-line reason rather than forcing a fake test around them.

**Criteria that depend on a pending integration** (`⚠ Stub` in the solution design) get type `pending-adapter`. They are not failed — the workflow is structurally correct; the adapter is the blocker. In the test plan, note what the criterion requires and reference the as-built activation recipe. In the test report, mark them `⏳ Pending adapter` with the activation steps inline. They do not block delivery — they are explicitly accepted residual items unless the engineer says otherwise.

**Static checks are one shared checklist, not itemized per criterion.** They validate structural correctness of what was built, independent of any specific acceptance criterion. Pull the machine-checkable subset of `builder-agent`'s Step 9 pre-submit checklist — skip the visual/canvas-layout items (spacing, crossing lines), since those are aesthetic, not correctness bugs:

```markdown
Expand Down Expand Up @@ -210,7 +212,7 @@ Once every case passes, or the engineer explicitly accepts a residual known issu
```

**Fields:**
- `type` — `static` (structural, no live call), `acceptance` (live job + outcome check), `artifact-inspection` (checks an artifact from a prior case), or `not-testable` (documented scope limitation, no execution)
- `type` — `static` (structural, no live call), `acceptance` (live job + outcome check), `artifact-inspection` (checks an artifact from a prior case), `not-testable` (documented scope limitation, no execution), or `pending-adapter` (criterion requires an integration marked `⚠ Stub` — not failed, not skipped; documented as an accepted residual with activation steps)
- `criterion` — the acceptance-criteria ID this case verifies, or `null` for static checks that apply to the whole build
- `check` / `verify` — human-readable enough that a different engineer could execute it manually if needed; this file is evidence, not just automation input

Expand Down Expand Up @@ -238,6 +240,7 @@ Once every case passes, or the engineer explicitly accepts a residual known issu
|---|---|---|---|
| AC-1 | Port is in the correct VLAN and mode after turn-up | PASS | Job `67d0...`, post-check shows vlan=100 mode=access |
| AC-8 | ITSM ticket is updated with results | FAIL | Job `67d1...` completed, but GET on the change request shows state unchanged — handed back to builder-agent 2026-07-02 |
| AC-9 | Notification sent via Slack | ⏳ Pending adapter | Slack adapter not installed. Stub workflow `stub-slack` runs cleanly; placeholder sets slackStatus=pending_adapter. Activate per as-built §Activate: Slack. |

## Re-runs

Expand Down
31 changes: 30 additions & 1 deletion .claude/skills/solution-arch-agent/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,12 @@ For each row in the spec's Capabilities table:
For each row in the spec's Integrations table:
- Found + Running? → **✓ Resolved** (record adapter name, app name)
- Found + Stopped? → **⚠ Warning** (needs to be started)
- Not found + Required? → **⚠ Blocked** (stop and discuss)
- Not found, required, adapter unavailable or customer details TBD? → **⚠ Stub** (proceed — Design produces stub artifacts)
- Not found, required, and nothing can be built without it? → **⚠ Blocked** (stop and discuss)
- Not found + Not Required? → **✗ Skipped**

**`⚠ Stub` vs `⚠ Blocked`:** Stub means the integration is required but not yet available — delivery proceeds by building stub workflows and placeholder tasks now, activating the real adapter later. Blocked means the entire delivery is gated on resolving this first (e.g., the main workflow can't be designed without data only this adapter provides). Rule of thumb: if at least one component can be built and tested without the adapter, it's Stub, not Blocked.

### Find Reuse Opportunities

Search `workflows.json` for existing workflows that match spec phases. Flag as **↻ Reuse** candidates.
Expand Down Expand Up @@ -297,6 +300,32 @@ The orchestrator is always the last thing built, after all children are tested.
└────┴──────────────────────────────┴─────────────────────┴──────────┘
```

For every `⚠ Stub` integration, add to the inventory:
- `integration-model-{name}.json` — OpenAPI 3.0.3 stub spec (Type: Integration Model, Action: Build)
- `stub-{name}` — stub connectivity workflow (Type: Stub Workflow, Action: Build)
- `integration-questions.md` — customer questionnaire (Type: Questionnaire, Action: Build — one file covers all pending integrations)

**Producing stub artifacts:**

`integration-model-{name}.json` — OpenAPI 3.0.3, minimal and use-case scoped:
- `info.title` — the adapter type name as it will appear in Itential (e.g., `Slack`, `AWX`) — this becomes the `app` and `locationType` field values in workflow tasks
- `info.description` — one line: what this integration does in this use case; append `— STUB: scope TBC with customer` if endpoints aren't yet confirmed
- `servers[].url` — use a `variables` block for unknown hostnames; add `"description": "STUB: confirm with customer"` to any unknown variable
- `components.securitySchemes` — mark `description` as `STUB: confirm auth method with customer` if not yet confirmed
- `paths` — only the operations the stub workflow will call; use accurate schemas where known

`integration-questions.md` — one section per pending integration, three-column table:

| Question | Why needed | Customer answer |
|----------|-----------|-----------------|
| Hostname / base URL | Needed to configure the adapter server | |
| Auth method (bearer / basic / API key) | Determines how credentials are stored | |
| Token source / how to obtain it | Needed to provision the adapter | |
| API version or path prefix differences | Affects endpoint wiring in workflows | |
| Firewall / IP allowlisting requirements | Platform must be able to reach this system | |

Close `integration-questions.md` with a **Next steps** note: once all questions are answered, update each integration model, provision the adapter, and replace placeholder tasks using the as-built activation recipes.

**E. Implementation Plan** — ordered build steps with test method for each

**F. Acceptance Criteria → Tests** — map each criterion to how to verify it. This is a first-pass mapping — `/qa-agent` refines it into an executable `test-plan.md` once real IDs exist after Build, but the verification *method* per criterion should be decided now, while the design is fresh.
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ Requirements → Feasibility → Design → Build → Test → As
23. **Adapter `app` ≠ adapter instance name** — The `app` and `locationType` fields on adapter tasks must be the adapter **type name** from `apps.json` (e.g., `EmailOpensource`, `Servicenow`), NOT the adapter **instance name** from `adapters.json` (e.g., `email`, `servicenow-prod`). Using the instance name causes `"No config found for Adapter: <name>"` at runtime. The `adapter_id` field is where the instance name goes. Triple-check: `app` = type, `adapter_id` = instance.
24. **Project-scoped asset names** — once an asset is added to a project, its `name` is prefixed with `@{projectId}: `. When reading or updating a project-owned asset via PUT, you MUST use the scoped name or the API returns 400. Read the asset first to get its current name, or construct it as `@{projectId}: {displayName}`. Strip this prefix when displaying names to the user.
25. **NEVER wire a Configuration Manager remediation task** — `runAutoRemediation`, `advancedAutoRemediation`, `convertChangesToConfig`, `patchDeviceConfiguration`, `advancedPatchDeviceConfiguration`, `patchCMDeviceConfiguration`, `ManualRemediation`, and `ManualRemediationResults` are prohibited in every workflow, even when a spec asks for fully automatic remediation. Golden Config detects and reports drift; it never applies fixes to a device. To correct a device, build a normal config-push delivery using the environment's config-push task (`sendConfig`/`runService` via GatewayManager, `itential_cli`, or netmiko send-config). See the `/itential-golden-config` Remediation section. (`updateNodeConfig` is allowed — it authors the GC node template, not a device.)
26. **Cloud/SaaS auth: use `/oauth/token`, not `/login`** — The `/login` endpoint returns 500 on cloud/SaaS instances; this is a server-side issue, not a credential problem. Always use `POST /oauth/token` with `grant_type=client_credentials` on cloud instances. If you see a 500 from `/login`, switch to OAuth — don't retry.
27. **Workflow variable path is flat** — Job output variables live at `.data.variables.{varName}`, not `.data.variables.job.{varName}`. The `.job` nesting does not exist. The wrong path silently returns null — no error, just missing data.
28. **Template `group` field cannot be empty string** — Passing `"group": ""` causes a validation error when creating or updating a Jinja2 or TextFSM template. Use a real group name or `"Default"`.
29. **Service account creation on cloud requires Admin Essentials** — On cloud instances, creating a service account for API access requires navigating to **Admin Essentials → Service Accounts**. This section is not accessible from the main navigation or standard user management screens.

## Helper JSON Templates

Expand Down
Loading