Skip to content
Merged
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,17 @@ After the loop runs, read the human activity view or consume its portable JSON:
```bash
fclt ai loop activity --project
fclt ai loop activity --project --json
fclt ai loop activity --all --json
fclt ai loop resolve <activity-action-locator> --json
```

The activity snapshot explains what agents captured, what sources were checked,
how repeated observations were correlated, the current disposition, linked
implementation work, and the next action. It is embedded in the immutable loop
report so later writeback edits cannot rewrite history.
Aggregate actionable items may carry an opaque locator. Resolution revalidates
the exact current scope and lifecycle revision and returns a plain-language
plan without guessing a root or performing a mutation.

### 3. Inspect existing AI state

Expand Down Expand Up @@ -584,6 +589,7 @@ Start with:
- [Built-in pack](./docs/built-in-pack.md): packaged work-unit, writeback, and evolution defaults
- [Built-in pack upgrades](./docs/pack-upgrades.md): non-destructive refresh behavior for existing `.ai` roots
- [Codex plugin](./docs/codex-plugin.md): installable Codex skills and MCP tools for fclt workflows
- [Activity action locators](./docs/activity-action-locators.md): read-only resolution from aggregate activity to one verified current target
- [Writeback and evolution](./docs/writeback-evolution.md): the feedback-loop workflow and review surfaces
- [Managed mode](./docs/managed-mode.md): when to let `fclt` write tool files
- [Roadmap](./docs/roadmap.md): current gaps and planned work
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Start with [Writeback and evolution](./writeback-evolution.md) for the product's
- [Built-in pack](./built-in-pack.md): the packaged operating-model layer for writeback and evolution.
- [Built-in pack upgrades](./pack-upgrades.md): non-destructive refresh behavior for existing `.ai` roots.
- [Codex plugin](./codex-plugin.md): installable Codex skills and MCP tools for fclt workflows.
- [Activity action locators](./activity-action-locators.md): resolve one aggregate activity item to a verified current target without guessing roots or performing mutation.
- [Managed mode](./managed-mode.md): when to let `fclt` write tool files, and how adoption works.
- [Security and trust](./security-trust.md): source trust, audit, secrets, and commit hygiene.
- [Automations](./automations.md): recurring Codex loops for learning review, evolution review, and tool-call audit.
Expand Down
109 changes: 109 additions & 0 deletions docs/activity-action-locators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Activity action locators

Aggregate activity can contain identical proposal, writeback, or signal ids in
more than one scope. An `actionLocator` lets a consumer ask fclt which exact
current target an item refers to without guessing a canonical root.

The CLI/JSON contract is authoritative:

```bash
fclt ai loop activity --json
fclt ai loop resolve <activity-action-locator> --json
```

The Codex plugin exposes the same read-only resolver as `fclt_registry` action
`activity_resolve`. Its input is exactly one `locator` string. It rejects
caller-supplied scope, cwd, root, path, argv, endpoint, token, token-env,
credential, approval, and mutation fields.

## Version 1 contract

`ActivityItem.actionLocator` is optional. Consumers must treat a missing
locator as read-only, handoff-only activity. This preserves compatibility with
older reports and with items for which fclt cannot issue a safe current action.

Version 1 locators use this opaque form:

```text
fclt-act-v1.<identity-digest>.<binding-digest>
```

Consumers must not decode, synthesize, alter, or route on either digest. The
identity digest binds the opaque aggregate scope id plus resource kind and
identity. The binding digest additionally binds the verified machine-local
runtime identity, latest activity run, queue revision, current resource
lifecycle revision, and one allowed action class.

The runtime identity is an opaque UUID persisted in the machine-local loop
configuration. fclt pairs it with a hash of the verified canonical root's
realpath and filesystem instance identity. Replacing a checkout at the same
path, copying runtime state, or redirecting an ancestor through a symlink does
not preserve that binding.

The locator contains no root, path, command arguments, URL, endpoint, token,
token environment variable, credential, or external-system authority.

## Resolution and expiration

Resolution is read-only. fclt searches its preferred machine-local Global and
project runtime registry, verifies the canonical root and runtime-state relationship,
and recomputes the locator from current state. A project state directory cannot
redirect a locator to another clone, worktree, moved root, or project merely by
reusing an internal proposal id.

A locator is state-bound rather than time-bound. It expires when any bound
fact changes, including:

- the latest activity run or queue revision
- proposal or resource lifecycle state
- the allowed action class
- project/runtime identity or canonical-root registration
- locator schema compatibility

Alternate caller-configured Global roots are not discoverable without accepting
caller authority, so their items intentionally omit locators and remain
handoff-only.

Always resolve immediately before presenting an action plan, and resolve again
before any later lifecycle command. Refresh aggregate activity after any
rejection; never repair a locator or guess a root.

## Resolution result

A successful version 1 response returns:

- exact opaque scope id and safe Global/project context
- resource kind and id
- activity run id and queue revision
- the one currently allowed action class
- a plain-language plan
- an explicit statement that no mutation was performed
- an explicit `available: false` mutation state
- the requirements a future separate mutation command must satisfy: explicit
approval and an atomic expected-binding revision check

The action classes are `review`, `decide`, `apply`, `verify`, and `handoff`.
They describe the safe next workflow class; they do not grant permission to
execute it.

## Fail-closed errors

| Code | Meaning | Recovery |
| --- | --- | --- |
| `invalid_locator` | The locator is malformed. | Refresh activity and use the returned locator unchanged. |
| `incompatible_locator` | The locator version is unsupported. | Update fclt or refresh with a compatible producer. |
| `locator_not_found` | No verified current scope/resource identity matches. This includes removed resources, missing state, moved or renamed roots, and cross-project replay. | Repair registration/state if appropriate, then refresh activity. |
| `stale_revision` | The activity run, queue revision, resource lifecycle, runtime identity, or allowed action class changed. | Refresh activity and resolve the new locator. |
| `duplicate_identity` | More than one verified current target matched. | Repair duplicate registration; fclt will not choose one. |
| `locator_not_issued` | Current state matches, but the current aggregate snapshot did not issue that locator. | Refresh activity and use only the returned locator. |

## Mutation boundary

Resolution never reviews, accepts, rejects, applies, verifies, edits canonical
capability, writes project or tool-home files, changes workflow state, or
mutates an external system. Those operations remain separate closed commands.
Locator-bound mutation is withheld in version 1 because existing lifecycle
commands do not accept an expected locator binding revision. A consumer must
not translate a plan into those commands. A future mutation contract must
atomically require explicit approval and the expected current binding; a
locator alone is never mutation authority.
17 changes: 17 additions & 0 deletions docs/codex-plugin-capability-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,23 @@
"rollback": "not_applicable",
"verification": "typed schema, aggregate default plus explicit filters, immutable activity snapshots, bounded targets and HTTP(S) links, no absolute paths, machine state keys, or credential-bearing URLs in portable activity JSON, queue continuity, and zero writes during preview"
},
{
"id": "evolution_loop.activity_action_resolution",
"cli": "ai loop resolve <activity-action-locator> --json",
"cliAvailability": "available",
"mcp": {
"disposition": "exposed",
"tool": "fclt_registry",
"action": "activity_resolve",
"reason": "the closed router accepts only one opaque versioned locator; caller-supplied scope, cwd, root, path, argv, endpoint, token, token env, credential, approval, and mutation fields are rejected"
},
"risk": "read_only",
"scope": "verified machine-local Global or project runtime identity selected only by the locator",
"preview": "revalidates the latest activity run, queue revision, current resource lifecycle, project/runtime identity, and allowed action class before returning a plain-language plan",
"apply": "withheld; version 1 exposes no locator-bound mutation because existing lifecycle commands do not accept the expected locator binding revision",
"rollback": "not_applicable; resolution performs zero canonical, tool-home, project, workflow, or external mutation",
"verification": "no-write snapshots, duplicate-id and duplicate-worktree isolation, cross-scope replay refusal, moved-root and missing-state refusal, stale lifecycle/run rejection, incompatible-version rejection, raw-field exclusion, and published typed-tool discovery"
},
{
"id": "autosync.mutation",
"cli": "autosync status|cleanup|uninstall|run --once",
Expand Down
3 changes: 2 additions & 1 deletion docs/codex-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ The plugin exposes:
- `fclt_workflow`: typed writeback and evolution read/review/lifecycle operations
- `fclt_sync`: managed-state inspection and dry-run sync preview
- `fclt_registry`: source search/verification, strict-trust install/update preview,
and bounded reconciliation status/review through a closed scope/window/source-id schema
bounded reconciliation status/review through a closed scope/window/source-id schema,
and read-only resolution of one opaque activity action locator
- `fclt_audit`: structured, redacted, non-interactive security audit with zero report or index writes
- `fclt_automation`: read-only autosync status plus scheduled evolution-loop status and preview
- `fclt_status`
Expand Down
10 changes: 10 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ fclt ai loop enable [--rrule <rrule>] [--source <id>] [--dry-run] [--json]
fclt ai loop disable [--dry-run] [--json]
fclt ai loop status [--json]
fclt ai loop activity [--all|--global|--project] [--json]
fclt ai loop resolve <activity-action-locator> [--json]
fclt ai loop run [--since <date>] [--until <date>] [--source <id>] [--dry-run] [--scheduled] [--json]
```

Expand Down Expand Up @@ -153,6 +154,15 @@ opaque `scopeId`, and `truncation` reports any bounded omissions. Aggregate
responses are capped before they reach CLI or plugin consumers; incomplete or
truncated coverage is never presented as complete.

Actionable items may include an optional opaque `actionLocator`. Resolve it
with `loop resolve` to obtain a read-only, plain-language plan for the exact
verified current scope and resource. Resolution accepts no root or scope flag,
performs no mutation, and fails closed when the activity run, queue revision,
resource lifecycle, allowed action class, or project/runtime identity changed.
Older or non-actionable items without a locator remain handoff-only. See
[Activity action locators](./activity-action-locators.md) for versioning and
error semantics.

`loop enable` is an explicit opt-in that installs an fclt-owned Codex
automation. The loop persists the full current queue, emits a delta for
notifications, retries bounded reconciliation failures, reports scheduler
Expand Down
4 changes: 4 additions & 0 deletions docs/writeback-evolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ approvals, verification state, and the next action.
The aggregate is contract version 2 and joins each version 1 feed to a stable
opaque scope id. Check its `truncation` object before treating the returned item
list as exhaustive.
Actionable items may include an opaque `actionLocator`. Resolve it with
`fclt ai loop resolve <locator> --json` to obtain a read-only plan for the
verified current scope and resource. Missing locators remain handoff-only;
consumers must never infer roots from scope labels or internal ids.
Each item also identifies its global or project context, typed capability
targets such as an instruction, skill, prompt, or automation, the reason for
the decision, and bounded HTTP(S) evidence links when the source supplied one.
Expand Down
Loading
Loading