Project-Local Lifecycle

Bundle lifecycle and graduation

Project-Local Artifact Lifecycle

Reference for managing project-local bundles across all five bundle types over their full lifetime: discovery → deploy or provider selection → conflict resolution → inspection → graduation → removal.

Layout

.aiwg/
├── extensions/<id>/    # Single-capability bundles
├── addons/<id>/        # Focused feature packs
├── frameworks/<id>/    # Complete workflow domains
├── plugins/<id>/       # Marketplace-packaged bundles
├── providers/<id>/     # Custom provider definitions
└── quickref.json       # Canonical project orientation definition (optional)

Each `<id>/` contains a `manifest.json`. Artifact-bearing bundles also contain artifacts (skills/, rules/, agents/, commands/). Provider bundles are metadata-only in phase 0: `providerConfig.extends` selects an existing writer adapter while preserving a custom provider id at the CLI boundary. Provider bundles may also declare `providerConfig.capabilities` as data-only overrides consumed by `aiwg steward capabilities --provider <custom>`. The directory is byte-identical in shape to its upstream counterpart at `agentic/code/{addons,frameworks,providers}/` so `aiwg promote` is a copy, not a migration.

Lifecycle commands

CommandAction
`aiwg new-bundle <name>`Scaffold a new bundle with manifest + starter + README
`aiwg new-provider <name>`Scaffold a custom provider bundle under `.aiwg/providers/`
`aiwg use <name>`Deploy a single project-local bundle to configured providers
`aiwg use <framework> --provider <custom>`Select a project-local provider bundle
`aiwg use <framework>`Deploys upstream + auto-deploys all project-local bundles
`aiwg list --project-local`List discovered bundles + validation status
`aiwg doctor --project-local`Health check: counts, validation, shadows, drift, matrix
`aiwg remove <name>`Revert deployed files; preserves source under `.aiwg/`
`aiwg promote <name>`Graduate a bundle to upstream or a corpus path
`aiwg activity-log show`Audit the lifecycle event log
`aiwg quickref generate --project`Render the deterministic project quickref skill
`aiwg quickref deploy --project`Deploy the quickref to configured provider kernel surfaces

Discovery

`aiwg use`, `aiwg doctor`, and `aiwg list --project-local` all run the same discovery scanner. It walks `.aiwg/{extensions,addons,frameworks}/` for content bundles, `.aiwg/plugins/` for marketplace delivery wrappers, and `.aiwg/providers/` for custom provider definitions. It validates each `manifest.json` against the canonical Zod schema and returns structured results.

What discovery enforces:

  • Manifest matches the JSON Schema (kebab-case ids, ≤ 64 KB, ≤ 200

bundles per project)

  • Bundle type matches its parent directory (`type: extension` lives

under `extensions/`)

  • No symlinked bundle directories (refused per threat model #1042)
  • No case-collision ids within the same type
  • Path-traversal attempts in entry paths are refused

Validation errors are surfaced — they never crash the operation.

Deploy

`aiwg use <bundle-name>` deploys a specific artifact-bearing project-local bundle. `aiwg use <framework>` (e.g., `sdlc`) deploys the upstream framework and all project-local bundles in the same pass.

Provider bundles are selected, not deployed as artifact bundles:

aiwg new-provider my-provider
aiwg use sdlc --provider my-provider

The generated manifest contains `providerConfig.extends` (default: `claude`). In phase 0, this delegates output writing to the existing provider adapter. It does not define new writer behavior or new filesystem targets by itself.

To customize steward guidance, add optional capability overrides:

{
  "providerConfig": {
    "extends": "codex",
    "displayName": "my-codex",
    "capabilities": {
      "nativeFeatures": { "cron": true },
      "emulation": { "mission_control": "aiwg-mc" }
    }
  }
}

Supported feature keys are `cron`, `agent_teams`, `tasks`, `mcp`, `behaviors`, `mission_control`, and `daemon`. Invalid feature keys fail manifest validation.

Per-bundle deploy: 1. Resolve shadows against the upstream registry 2. Refuse to deploy bundles with safety-critical shadows that lack explicit `overrides:` declarations (or with phantom overrides, or with cross-bundle artifact-id collisions) 3. Run `tools/agents/deploy-agents.mjs` with `--source` pointing at the bundle directory 4. Compute SHA-256 of every artifact and persist as `artifactHashes` in the registry — used later by `aiwg remove` and `aiwg doctor` for drift detection 5. Emit `deploy` (or `deploy-failed`) to the activity log

`--dry-run` and `--no-project-local` are supported.

When `.aiwg/quickref.json` exists, each project-local deploy also regenerates and refreshes that provider's project quickref. The generated skill stays short: it states local precedence and points to indexed assets rather than embedding their full bodies. See Project Quickrefs.

Conflict resolution (shadow policy)

When a project-local artifact has the same id as an upstream artifact, the resolver chooses one of seven verdicts (ADR #1041):

#CaseDefault`--force`?
1No collisiondeployn/a
2Non-safety-critical shadowdeploy + warnn/a
3Safety-critical shadow + explicit `overrides:`deploy with prominent warningn/a
4Safety-critical shadow without `overrides:`refuserefuse (force does NOT bypass)
5Phantom override (`overrides: ["nonexistent"]`)refuserefuse
6Two project-local bundles export same artifactrefuse bothrefuse both
7Git-installed (cache) shadowsame as cases 2/3/4 against the cachen/a

To shadow a safety-critical upstream artifact intentionally, declare it:

{
  "type": "extension",
  "id": "my-overrides",
  "overrides": ["human-authorization"],
  ...
}

The override is logged as `shadow-acknowledged` in the activity log and prominently warned in deploy output and `aiwg doctor`.

Inspection: `aiwg doctor`

aiwg doctor                       # general health + project-local section
aiwg doctor --project-local       # only the project-local section
aiwg doctor --quiet               # suppress informational subsections

The project-local section reports:

  • Per-type counts with bundle id listing
  • Validation errors (top 10 inline, "+N more" if longer)
  • Active shadows (informational ⚠ for non-safety, !! for acknowledged)
  • Denylist violations (✗)
  • Drift — deployed file hash differs from registered `artifactHashes`
  • Provider deployment matrix

Doctor exits 0 when there are no validation errors, no denylist violations, and no drift. Shadows alone do not fail doctor (they're informational).

Removal: `aiwg remove`

aiwg remove <name>                          # default: refuse case-2 mutations
aiwg remove <name> --force                  # also delete operator-edited files
aiwg remove <name> --provider claude        # limit to one provider
aiwg remove <name> --dry-run                # plan only
aiwg remove <name> --keep-registry          # revert files but keep entry

Source under `.aiwg/<type>/<name>/` is never deleted by `aiwg remove`. `--force` skips the case-2 prompt only — it does not authorize destroying another bundle's deploy (case 4) and does not bypass OS permission errors (case 5).

For the full per-case revert behavior, see `design-aiwg-remove-revert.md`.

Graduation: `aiwg promote`

When a bundle proves out and you want to move it from project-local to upstream (or to a private corpus path):

aiwg promote <name>                          # default: --to upstream
aiwg promote <name> --to corpus ~/my-corpus/ # to a private path
aiwg promote <name> --dry-run                # preview
aiwg promote <name> --cleanup                # remove .aiwg source after copy
aiwg promote <name> --force                  # override @-ref refusal

What promote does: 1. Discovers the bundle 2. Refuses if the destination already exists (must `aiwg remove` from upstream first) 3. Refuses if the bundle contains `@.aiwg/` references (they'd dangle after the move) — `--force` overrides 4. SHA-256 snapshots every source file 5. Recursive copy to the destination (`agentic/code/addons/<name>/` for extension/addon/plugin, `agentic/code/frameworks/<name>/` for framework, `agentic/code/providers/<name>/` for provider) 6. Re-hashes every destination file; rolls back (deletes the dest directory) on any mismatch 7. Updates the registry: `source: 'project-local'` → `'bundled'` (or `'corpus'`) 8. Optionally removes the `.aiwg/<type>/<name>/` source (`--cleanup`) 9. Emits `promote` (or `promote-failed`) to the activity log

The hash-verify step makes the identical-form invariant a runtime guarantee, not a convention.

Activity log

Every project-local lifecycle event writes a single line to `.aiwg/activity.log` in the canonical format:

## [YYYY-MM-DD HH:MM] <op> | <event>: <name>:<type> | <summary>

The 12 events:

  • `discover` — new manifest detected (deduped)
  • `deploy`, `deploy-failed`
  • `conflict`, `shadow-acknowledged`, `shadow-refused`
  • `remove`, `remove-mutated`, `remove-conflict`, `remove-force`
  • `promote`, `promote-failed`

Query:

aiwg activity-log show              # full log
aiwg activity-log stats             # counts by op

Writes are non-blocking: if the log can't be written, the underlying operation still succeeds.

When project-local is the wrong answer

Project-local is the right answer for personal or single-team customization that you want to graduate later or never share. It is the wrong answer for:

  • Customizations destined for the public AIWG marketplace — author

upstream and use a plugin

  • Cross-project customizations shared across many of your repositories —

use a corpus path with `aiwg promote --to corpus <path>` and reference via aiwg config

  • Forking AIWG itself — only when you need to change AIWG core, not when

you're adding addons/extensions

For the migration story, see the forking guide.

See also