@odla-ai/cli 0.27.3 → 0.27.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -16
- package/dist/bin.cjs +631 -216
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-JWEBGIBR.js → chunk-DQOJ4S6H.js} +634 -219
- package/dist/chunk-DQOJ4S6H.js.map +1 -0
- package/dist/index.cjs +631 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +29 -5
- package/skills/odla/references/agent-identity.md +125 -0
- package/skills/odla/references/pm-work-intake.md +131 -0
- package/skills/odla/references/pm.md +139 -11
- package/skills/odla/references/sdks.md +5 -4
- package/skills/odla-migrate/references/project-state.md +8 -2
- package/dist/chunk-JWEBGIBR.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -501,6 +501,8 @@ interface OdlaProjectConfig {
|
|
|
501
501
|
publicRead?: string[];
|
|
502
502
|
};
|
|
503
503
|
ai?: {
|
|
504
|
+
/** Hosted is the default when omitted; provider-only legacy configs are BYOK. */
|
|
505
|
+
mode?: "hosted" | "byok";
|
|
504
506
|
provider?: string;
|
|
505
507
|
model?: string;
|
|
506
508
|
/** Env var containing the provider key to store in the platform vault. */
|
|
@@ -829,7 +831,7 @@ interface DoctorOptions {
|
|
|
829
831
|
* It then collects warnings for the mistakes provision can't fix silently: a
|
|
830
832
|
* schema with no entities, a rules namespace with no matching entity, an
|
|
831
833
|
* integration with incomplete rules or a seed targeting an unknown namespace, the `ai`
|
|
832
|
-
* service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
834
|
+
* BYOK service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
833
835
|
* an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
|
|
834
836
|
* will be skipped), and — when `o11y` is enabled — any env whose local
|
|
835
837
|
* credentials lack an ingest token. It also folds in the shared rule linter,
|
|
@@ -864,9 +866,9 @@ interface InitOptions {
|
|
|
864
866
|
* written when it doesn't already exist unless `force` is set (otherwise it
|
|
865
867
|
* throws); the schema/rules files are written only when missing (never
|
|
866
868
|
* overwritten, even with `force`). `appId` must match `^[a-z0-9][a-z0-9-]*$` or
|
|
867
|
-
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
|
|
868
|
-
*
|
|
869
|
-
* `
|
|
869
|
+
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`, and
|
|
870
|
+
* platform-hosted AI. Passing `aiProvider` explicitly opts into BYOK and also
|
|
871
|
+
* picks its `keyEnv`.
|
|
870
872
|
*
|
|
871
873
|
* @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
|
|
872
874
|
* @param options.name Human-readable app name embedded in the config.
|
|
@@ -874,7 +876,7 @@ interface InitOptions {
|
|
|
874
876
|
* @param options.configPath Config filename relative to root (default `odla.config.mjs`).
|
|
875
877
|
* @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
|
|
876
878
|
* @param options.services Enabled services (default `["db","ai"]`).
|
|
877
|
-
* @param options.aiProvider
|
|
879
|
+
* @param options.aiProvider Optional provider slug; supplying it opts into BYOK.
|
|
878
880
|
* @param options.force Overwrite an existing config file instead of throwing.
|
|
879
881
|
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
880
882
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -501,6 +501,8 @@ interface OdlaProjectConfig {
|
|
|
501
501
|
publicRead?: string[];
|
|
502
502
|
};
|
|
503
503
|
ai?: {
|
|
504
|
+
/** Hosted is the default when omitted; provider-only legacy configs are BYOK. */
|
|
505
|
+
mode?: "hosted" | "byok";
|
|
504
506
|
provider?: string;
|
|
505
507
|
model?: string;
|
|
506
508
|
/** Env var containing the provider key to store in the platform vault. */
|
|
@@ -829,7 +831,7 @@ interface DoctorOptions {
|
|
|
829
831
|
* It then collects warnings for the mistakes provision can't fix silently: a
|
|
830
832
|
* schema with no entities, a rules namespace with no matching entity, an
|
|
831
833
|
* integration with incomplete rules or a seed targeting an unknown namespace, the `ai`
|
|
832
|
-
* service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
834
|
+
* BYOK service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
833
835
|
* an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
|
|
834
836
|
* will be skipped), and — when `o11y` is enabled — any env whose local
|
|
835
837
|
* credentials lack an ingest token. It also folds in the shared rule linter,
|
|
@@ -864,9 +866,9 @@ interface InitOptions {
|
|
|
864
866
|
* written when it doesn't already exist unless `force` is set (otherwise it
|
|
865
867
|
* throws); the schema/rules files are written only when missing (never
|
|
866
868
|
* overwritten, even with `force`). `appId` must match `^[a-z0-9][a-z0-9-]*$` or
|
|
867
|
-
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
|
|
868
|
-
*
|
|
869
|
-
* `
|
|
869
|
+
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`, and
|
|
870
|
+
* platform-hosted AI. Passing `aiProvider` explicitly opts into BYOK and also
|
|
871
|
+
* picks its `keyEnv`.
|
|
870
872
|
*
|
|
871
873
|
* @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
|
|
872
874
|
* @param options.name Human-readable app name embedded in the config.
|
|
@@ -874,7 +876,7 @@ interface InitOptions {
|
|
|
874
876
|
* @param options.configPath Config filename relative to root (default `odla.config.mjs`).
|
|
875
877
|
* @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
|
|
876
878
|
* @param options.services Enabled services (default `["db","ai"]`).
|
|
877
|
-
* @param options.aiProvider
|
|
879
|
+
* @param options.aiProvider Optional provider slug; supplying it opts into BYOK.
|
|
878
880
|
* @param options.force Overwrite an existing config file instead of throwing.
|
|
879
881
|
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
880
882
|
*/
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.5",
|
|
4
4
|
"description": "Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/cli",
|
package/skills/odla/SKILL.md
CHANGED
|
@@ -10,6 +10,7 @@ runbookOrder:
|
|
|
10
10
|
- references/build.md
|
|
11
11
|
- references/sdks.md
|
|
12
12
|
- references/pm.md
|
|
13
|
+
- references/agent-identity.md
|
|
13
14
|
- references/co-owners.md
|
|
14
15
|
---
|
|
15
16
|
|
|
@@ -151,19 +152,39 @@ on the app. It is platform-side: there is nothing PM-specific to install or
|
|
|
151
152
|
provision. Start a session by reading it, and keep it current while you build:
|
|
152
153
|
|
|
153
154
|
```cmd
|
|
154
|
-
npx @odla-ai/cli pm
|
|
155
|
+
npx @odla-ai/cli pm next --app <appId>
|
|
155
156
|
```
|
|
156
157
|
|
|
158
|
+
For a durable supervisor loop, establish and persist an exact-project PM cursor:
|
|
159
|
+
|
|
160
|
+
```cmd
|
|
161
|
+
npx @odla-ai/cli pm watch --app <appId> --entity task --jsonl
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
A Ready event is a wake-up signal, not permission: reload the task and linked
|
|
165
|
+
goal and win the current revision's atomic claim before starting. PM-attached
|
|
166
|
+
comments use the same cursor (`--action comment.created`); general Discussion
|
|
167
|
+
topics and mentions still use `discuss watch`.
|
|
168
|
+
|
|
157
169
|
The app must already be registered for ownership-scoped PM access. On a new
|
|
158
170
|
project, use a focused commit/checkpoint only until the first provision, then
|
|
159
171
|
initialize PM and backfill the approved early evidence immediately. Across
|
|
160
172
|
several efforts, list without `--app` first, then scope every write to the exact
|
|
161
173
|
project id.
|
|
162
174
|
|
|
163
|
-
|
|
164
|
-
**
|
|
165
|
-
|
|
166
|
-
|
|
175
|
+
Before project-mutating work, confirm the request aligns to an open goal and
|
|
176
|
+
propose/refine a **task** in Backlog. Ready is a planner handoff: an ordinary
|
|
177
|
+
managed-agent grant has `pm.execute`, so a human owner or `pm.plan` agent must
|
|
178
|
+
approve the Ready contract before the executor claims its reviewed revision.
|
|
179
|
+
Record a **decision** the moment you make one (with what it rules out), and file
|
|
180
|
+
a **bug** the moment you notice one. A decision you don't record is one the next
|
|
181
|
+
agent re-litigates. Full command set, conventions, and recovery procedure:
|
|
182
|
+
`references/pm.md` and `references/pm-work-intake.md`.
|
|
183
|
+
|
|
184
|
+
For an agent that spans linked worktrees or customer repositories, follow
|
|
185
|
+
`references/agent-identity.md`: select a named context and verify the same
|
|
186
|
+
immutable, project-derived handle is requested and human-approved when
|
|
187
|
+
reconnecting an expired credential.
|
|
167
188
|
|
|
168
189
|
## Operational runbooks live in the database, not in this bundle
|
|
169
190
|
|
|
@@ -289,6 +310,9 @@ code, paste a publishable key, run a command) — and wait for a nod.
|
|
|
289
310
|
- `references/pm.md` — the project manager for agents: goals, board, decisions,
|
|
290
311
|
bugs. What to file where, the `pm` command set, and how to open and close a
|
|
291
312
|
session against it.
|
|
313
|
+
- `references/agent-identity.md` — preserve one attributable agent principal
|
|
314
|
+
across credential expiry, linked worktrees, and non-odla-ai projects without
|
|
315
|
+
copying a token or widening project authority.
|
|
292
316
|
- `references/co-owners.md` — sharing one app's db and tooling across a team:
|
|
293
317
|
`app owners add/list/remove`, and how each co-owner self-provisions their own
|
|
294
318
|
credentials (dev and the shared prod database) without any secret handoff.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Reconnect an agent across worktrees and projects
|
|
2
|
+
|
|
3
|
+
Use this procedure when an agent must keep the same attributable identity while
|
|
4
|
+
its short-lived device credential expires, or when it operates outside the
|
|
5
|
+
checkout that first obtained the credential.
|
|
6
|
+
|
|
7
|
+
## Preconditions
|
|
8
|
+
|
|
9
|
+
- The human approving the request owns or co-owns every selected project.
|
|
10
|
+
- The handshake contains one deliberate handle suffix, such as `customer-app`
|
|
11
|
+
or `release-reviewer`. The Registry places it under the approving human's
|
|
12
|
+
verified namespace (for example, `@cory/customer-app`). The CLI derives this
|
|
13
|
+
suffix deterministically from the exact project; SDK callers may explicitly
|
|
14
|
+
request a different stable `agentHandle` for a cross-project agent.
|
|
15
|
+
- No token, credential file, or browser session is copied between worktrees,
|
|
16
|
+
machines, people, or chat messages.
|
|
17
|
+
|
|
18
|
+
## 1. Save non-secret context outside the checkout
|
|
19
|
+
|
|
20
|
+
```cmd
|
|
21
|
+
npx @odla-ai/cli context save delivery --platform https://odla.ai --app <appId> --env prod
|
|
22
|
+
npx @odla-ai/cli context show --context delivery --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The context stores only platform/app/environment metadata. Its private token
|
|
26
|
+
cache lives under `~/.odla/profiles/delivery/`, independently of any repository
|
|
27
|
+
or linked worktree. Select it explicitly with `--context delivery` or
|
|
28
|
+
`ODLA_CONTEXT=delivery`; there is no ambient current context.
|
|
29
|
+
|
|
30
|
+
## 2. Establish the durable principal
|
|
31
|
+
|
|
32
|
+
Run the intended command with the named context. If no valid cached credential
|
|
33
|
+
exists, the CLI starts the normal email-bound device handshake and prints the
|
|
34
|
+
exact Studio approval URL.
|
|
35
|
+
|
|
36
|
+
```cmd
|
|
37
|
+
npx @odla-ai/cli whoami --context delivery --email <account-email> --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
In Studio, review the exact code, requested handle, projects, and capabilities.
|
|
41
|
+
The request is immutable: approval cannot edit its identity or grants. The
|
|
42
|
+
handle—not the request label or local context name—is the durable agent identity
|
|
43
|
+
key. Record the full verified handle in the agent handoff; never record the
|
|
44
|
+
token. A normal CLI handshake derives the same handle from the configured
|
|
45
|
+
project in every checkout and worktree.
|
|
46
|
+
|
|
47
|
+
After approval and collection, verify the selected identity and context:
|
|
48
|
+
|
|
49
|
+
```cmd
|
|
50
|
+
npx @odla-ai/cli whoami --context delivery --json
|
|
51
|
+
npx @odla-ai/cli pm next --context delivery --json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If the agent request omits the handle, Registry deliberately creates a new
|
|
55
|
+
principal for that handshake. An untrusted request label can therefore never
|
|
56
|
+
select an existing agent.
|
|
57
|
+
|
|
58
|
+
## 3. Reconnect after expiry
|
|
59
|
+
|
|
60
|
+
Re-run the command with the same named context and project. The cache keeps the
|
|
61
|
+
approved account identifier and starts a fresh handshake when the token is
|
|
62
|
+
expired. During human review:
|
|
63
|
+
|
|
64
|
+
1. verify the immutable request contains the expected existing handle suffix;
|
|
65
|
+
2. verify every exact requested project should receive access now;
|
|
66
|
+
3. review optional capabilities again; and
|
|
67
|
+
4. approve the request unchanged, or decline it with corrective feedback.
|
|
68
|
+
|
|
69
|
+
Registry binds the new credential to the existing managed-agent principal and
|
|
70
|
+
stores the human's reviewed exact-project set without activating it yet. The
|
|
71
|
+
existing principal's authoritative name and purpose are retained; reusing its
|
|
72
|
+
handle is not a profile-edit operation. Approval alone leaves the current
|
|
73
|
+
credential and its project grants usable. When the replacement plaintext is
|
|
74
|
+
successfully collected, Registry atomically clears that plaintext, retires
|
|
75
|
+
older collected ordinary-handshake credentials, and replaces the principal's
|
|
76
|
+
manager-issued project grants with the reviewed set. Newly selected projects
|
|
77
|
+
are unavailable before collection, and omitted projects are revoked during the
|
|
78
|
+
switch. If collection never succeeds, the working credential and grants are not
|
|
79
|
+
stranded by the approval.
|
|
80
|
+
|
|
81
|
+
Verify `whoami` reports the same principal/handle before resuming work. Ordinary
|
|
82
|
+
reviewed project access includes `pm.execute` but not `pm.plan`: re-read `pm
|
|
83
|
+
next` and claim the current Ready task revision, while leaving Ready approval to
|
|
84
|
+
a human owner or explicit planner. Identity continuity alone does not preserve
|
|
85
|
+
a stale claim or imply authority outside the newly reviewed grants.
|
|
86
|
+
|
|
87
|
+
## 4. Review remaining credentials
|
|
88
|
+
|
|
89
|
+
Successful collection automatically retires the preceding collected ordinary
|
|
90
|
+
handshake credential for that principal. Verify the old row in Studio's
|
|
91
|
+
agent-credential inventory has a `system:handshake-reconnect:<handshake-id>`
|
|
92
|
+
revocation reason. Do not delete a local cache as a substitute for this
|
|
93
|
+
server-side evidence.
|
|
94
|
+
|
|
95
|
+
The rotation set deliberately excludes manually minted credentials and
|
|
96
|
+
separately scoped handshakes: those may represent another deliberate runtime,
|
|
97
|
+
not a stale copy of this context. Review and revoke them explicitly when they
|
|
98
|
+
are no longer intended.
|
|
99
|
+
|
|
100
|
+
Project grants are still time-bounded. Collection makes the newly reviewed
|
|
101
|
+
selection authoritative for the principal: selected projects receive new
|
|
102
|
+
revisions and every live manager-issued project omitted from that selection is
|
|
103
|
+
revoked. There is not yet a non-interactive `auth rotate` command or OS
|
|
104
|
+
credential-store integration. The named context plus stable handle solves
|
|
105
|
+
worktree/project portability and principal continuity, but it is not ambient or
|
|
106
|
+
permanent authority.
|
|
107
|
+
|
|
108
|
+
## Recovery and audit evidence
|
|
109
|
+
|
|
110
|
+
- `handshake_pending`: approve the existing code and rerun the same command; do
|
|
111
|
+
not create a substitute request.
|
|
112
|
+
- Wrong handle requested: decline it and correct the project/SDK request before
|
|
113
|
+
starting a fresh handshake. If already approved, revoke the new credential in
|
|
114
|
+
Studio; do not rename or merge principals by editing local metadata.
|
|
115
|
+
- Missing project after reconnect: start a new reviewed handshake and select the
|
|
116
|
+
exact project; never widen to all projects.
|
|
117
|
+
- Project ownership/lifecycle changed after approval: collection expires the
|
|
118
|
+
unusable replacement while preserving the current credential and grant set.
|
|
119
|
+
Restore the intended project state, then start and review a fresh handshake.
|
|
120
|
+
- Lost local cache: save/select the same non-secret context, complete a new
|
|
121
|
+
handshake with the same handle, verify `whoami`, then revoke the lost
|
|
122
|
+
credential from Studio.
|
|
123
|
+
|
|
124
|
+
Audit evidence is the stable principal id/handle, the new credential id, and the
|
|
125
|
+
monotonic project-grant revision shown by Registry—not possession of a token.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# PM work intake — align, ready, claim, and recover
|
|
2
|
+
|
|
3
|
+
Use this runbook whenever an agent is about to begin project-mutating work.
|
|
4
|
+
PM goals and tasks are the durable records. Discussion is the communication
|
|
5
|
+
channel. A Codex Goal, when the harness supports it, is the execution objective
|
|
6
|
+
for the current chat and should name the PM goal and task references.
|
|
7
|
+
|
|
8
|
+
## Preconditions
|
|
9
|
+
|
|
10
|
+
- Resolve the exact `appId`; do not infer it from the repository name.
|
|
11
|
+
- Use a task-owned worktree and branch before editing.
|
|
12
|
+
- Never put a credential, token, or secret in PM or Discussion.
|
|
13
|
+
- A question, investigation, or alignment conversation may proceed without a
|
|
14
|
+
claim. Implementation may not.
|
|
15
|
+
|
|
16
|
+
## 1. Resolve context and read authoritative state
|
|
17
|
+
|
|
18
|
+
```cmd
|
|
19
|
+
npx @odla-ai/cli context show --context <profile>
|
|
20
|
+
npx @odla-ai/cli pm next --app <appId> --json
|
|
21
|
+
npx @odla-ai/cli pm handoff --app <appId> --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Read any existing Doing task before selecting another. For each candidate, read
|
|
25
|
+
the task, its goal, and their comments. If the current chat has a Codex Goal,
|
|
26
|
+
confirm that its objective and verification still match these records.
|
|
27
|
+
|
|
28
|
+
## 2. Check alignment
|
|
29
|
+
|
|
30
|
+
Match the requested outcome to an open PM goal. If none fits:
|
|
31
|
+
|
|
32
|
+
1. explain the mismatch to the user in Discussion/chat;
|
|
33
|
+
2. ask whether to refine or create a PM goal, defer the request, or accept a
|
|
34
|
+
narrowly scoped exception;
|
|
35
|
+
3. record an approved exception as an accepted PM decision and link its id from
|
|
36
|
+
the task;
|
|
37
|
+
4. do not begin implementation while the choice is unresolved.
|
|
38
|
+
|
|
39
|
+
An agent must not create a convenient goal merely to authorize itself.
|
|
40
|
+
|
|
41
|
+
## 3. Refine Backlog work and mark it Ready
|
|
42
|
+
|
|
43
|
+
Ready is a durable planner-to-executor handoff. A human project owner or an
|
|
44
|
+
agent holding `pm.plan` may refine the task and mark it Ready. Ordinary managed
|
|
45
|
+
agent handshakes receive `pm.execute`, not `pm.plan`: they may create a Backlog
|
|
46
|
+
proposal or file a bug, but must ask the user/planner to review the contract and
|
|
47
|
+
perform the Ready transition. Do not treat a 403 as a reason to widen or bypass
|
|
48
|
+
the grant.
|
|
49
|
+
|
|
50
|
+
Create/refine the task with one alignment source, an actionable description,
|
|
51
|
+
acceptance criteria, and execution mode:
|
|
52
|
+
|
|
53
|
+
```cmd
|
|
54
|
+
npx @odla-ai/cli pm task add --app <appId> --title "<work>" --goal <goal-id> --description "<bounded work>" --acceptance "<observable proof>" --execution agent
|
|
55
|
+
npx @odla-ai/cli pm task get <task-id> --json
|
|
56
|
+
npx @odla-ai/cli pm task ready <task-id> --expected-revision <revision>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use `--alignment-decision <decision-id>` instead of `--goal` only for an
|
|
60
|
+
accepted exception. Ready is stored as `column: "todo"` for wire compatibility.
|
|
61
|
+
The server rejects Ready when the goal/decision belongs to another project, the
|
|
62
|
+
goal is not open, the decision is not accepted, or the contract is incomplete.
|
|
63
|
+
|
|
64
|
+
## 4. Claim, then create the execution workspace
|
|
65
|
+
|
|
66
|
+
Claim and release require `pm.execute`. Planning authority alone is
|
|
67
|
+
intentionally insufficient, so the principal that approves a task does not
|
|
68
|
+
silently become its executor.
|
|
69
|
+
|
|
70
|
+
Review the latest task revision immediately before claiming:
|
|
71
|
+
|
|
72
|
+
```cmd
|
|
73
|
+
npx @odla-ai/cli pm task get <task-id> --json
|
|
74
|
+
npx @odla-ai/cli pm task claim <task-id> --expected-revision <revision>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Only one concurrent caller can win. On conflict, reload `pm next` and the task;
|
|
78
|
+
do not retry with a guessed revision. Once claimed, use the repository's
|
|
79
|
+
worktree procedure and mention the PM references in the execution chat:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
@[Task title](pm:task/<task-id>)
|
|
83
|
+
@[Goal title](pm:goal/<goal-id>)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 5. Execute, review, and complete
|
|
87
|
+
|
|
88
|
+
- Keep the task description/acceptance criteria current under its revision.
|
|
89
|
+
- Record decisions when the implementation closes off an alternative.
|
|
90
|
+
- File defects as bugs rather than burying them in progress prose.
|
|
91
|
+
- Comment with verification commands, evidence, commit/candidate identity, and
|
|
92
|
+
remaining risk.
|
|
93
|
+
- Move Doing to Review when the acceptance evidence is ready.
|
|
94
|
+
- Mark Done only after review and proof; mark the goal met only when all linked
|
|
95
|
+
work is resolved and the goal proof passes.
|
|
96
|
+
|
|
97
|
+
## 6. Release or recover
|
|
98
|
+
|
|
99
|
+
If the claimant must stop:
|
|
100
|
+
|
|
101
|
+
```cmd
|
|
102
|
+
npx @odla-ai/cli pm task release <task-id> --expected-revision <revision>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Comment with the branch/worktree, last verified commit, unfinished step, and
|
|
106
|
+
safe next action. An agent may release only its own claim; a human project
|
|
107
|
+
operator may recover an abandoned claim. Claims do not yet have automatic
|
|
108
|
+
leases, so never leave one active as a substitute for a handoff.
|
|
109
|
+
|
|
110
|
+
## 7. Resume safely
|
|
111
|
+
|
|
112
|
+
Establish a checkpoint before waiting for PM lifecycle changes, persist every
|
|
113
|
+
checkpoint record, and resume with its opaque cursor:
|
|
114
|
+
|
|
115
|
+
```cmd
|
|
116
|
+
npx @odla-ai/cli pm watch --app <appId> --entity task --jsonl
|
|
117
|
+
npx @odla-ai/cli pm watch --app <appId> --cursor <cursor> --entity task --state ready --self <principal-id> --jsonl
|
|
118
|
+
npx @odla-ai/cli pm watch --app <appId> --cursor <cursor> --entity task --action comment.created --self <principal-id> --jsonl
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Delivery is at least once. Deduplicate by `eventId`; advance durable consumer
|
|
122
|
+
state only on a `checkpoint` record. Filters consume nonmatching events and
|
|
123
|
+
still advance the checkpoint, so do not reuse a filtered consumer cursor for a
|
|
124
|
+
different policy. If the command reports `checkpoint_required` (exit 3), discard
|
|
125
|
+
the stale cursor, run `pm next` and reload any active task, then establish a new
|
|
126
|
+
checkpoint without `--cursor`.
|
|
127
|
+
|
|
128
|
+
A Ready event or PM-attached comment is only a wake-up signal. Before acting,
|
|
129
|
+
re-run `pm next`, reload the task revision, re-check its goal, and win `task
|
|
130
|
+
claim`. General Discussion topics and mentions stay on `discuss watch`; a chat
|
|
131
|
+
message still does not prove a task is Ready or grant execution authority.
|
|
@@ -57,7 +57,11 @@ npx @odla-ai/cli pm bug list --app <appId> --status open
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
```cmd
|
|
60
|
-
npx @odla-ai/cli pm
|
|
60
|
+
npx @odla-ai/cli pm next --app <appId>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```cmd
|
|
64
|
+
npx @odla-ai/cli pm task claim <id> --expected-revision <n>
|
|
61
65
|
```
|
|
62
66
|
|
|
63
67
|
```cmd
|
|
@@ -66,7 +70,9 @@ npx @odla-ai/cli pm decision list --q "stripe"
|
|
|
66
70
|
|
|
67
71
|
- `add` needs `--app <appId>` and `--title`; it takes the entity's own fields
|
|
68
72
|
(`--proof`, `--target` for goals; `--column`, `--goal`, `--assignee`, `--due`
|
|
69
|
-
for tasks; `--body` for decisions; `--severity`, `--desc` for bugs).
|
|
73
|
+
for tasks; `--body` for decisions; `--severity`, `--desc` for bugs). A task
|
|
74
|
+
created directly in `todo` (Ready) also needs an open goal or accepted
|
|
75
|
+
alignment decision, a description, and `--acceptance`.
|
|
70
76
|
- `list` filters with `--status`, `--severity`, `--column`, `--assignee`,
|
|
71
77
|
`--goal`, full-text `--q`, and pages with `--limit` / `--offset`. **With no
|
|
72
78
|
`--app` it spans every project you co-own** — that is the cross-project view,
|
|
@@ -77,21 +83,49 @@ npx @odla-ai/cli pm decision list --q "stripe"
|
|
|
77
83
|
- `comment <id> --body "…"` and `comments <id>` are the item's discussion thread.
|
|
78
84
|
Status and column changes post there automatically, so the thread is the audit
|
|
79
85
|
trail — the human sees what you did without asking.
|
|
80
|
-
- `rm <id>` deletes. Prefer `done` or a status change
|
|
86
|
+
- `rm <id>` deletes the current row. Prefer `done` or a status change: the
|
|
87
|
+
authorized immutable event log retains the deletion snapshot for recovery and
|
|
88
|
+
audit until the exact project lifetime is purged.
|
|
89
|
+
- `next --app <appId>` is the read-only intake view: open goals, current Doing
|
|
90
|
+
work, and Ready candidates. It never claims or mutates work.
|
|
91
|
+
- `watch --app <appId> --jsonl` establishes and resumes an exact-project PM
|
|
92
|
+
lifecycle cursor. Persist checkpoint records, deduplicate at-least-once
|
|
93
|
+
delivery by `eventId`, and use `--entity`, `--state`, `--by`, or `--self` for
|
|
94
|
+
one stable consumer policy.
|
|
95
|
+
- `task ready <id> --expected-revision <n>` validates and records the Ready
|
|
96
|
+
contract. `task claim` atomically moves the reviewed Ready revision to Doing;
|
|
97
|
+
`task release` explicitly returns an active claim to Ready. A stale revision
|
|
98
|
+
or concurrent claim is a conflict, so reload instead of overwriting it.
|
|
99
|
+
|
|
100
|
+
Task authority has an intentional handshake boundary. `pm.plan` may refine,
|
|
101
|
+
delete, or mark tasks Ready but cannot claim them. `pm.execute` may create
|
|
102
|
+
Backlog proposals and findings, claim/release, and move its claimed work through
|
|
103
|
+
Review and Done, but cannot approve Ready or change the task contract. Ordinary
|
|
104
|
+
managed-agent approval includes `pm.execute`; it does not include `pm.plan`.
|
|
105
|
+
Human project owners retain planning authority through ownership. Legacy
|
|
106
|
+
`pm.write` grants remain executable so existing claims are not stranded, but do
|
|
107
|
+
not gain planning authority.
|
|
81
108
|
|
|
82
109
|
## Working with it
|
|
83
110
|
|
|
84
|
-
**At the start of a session**, read before you
|
|
111
|
+
**At the start of a session**, resolve the exact project and read before you
|
|
112
|
+
write:
|
|
85
113
|
|
|
86
114
|
```cmd
|
|
87
|
-
npx @odla-ai/cli
|
|
115
|
+
npx @odla-ai/cli context show --context <profile>
|
|
116
|
+
npx @odla-ai/cli pm next --app <appId>
|
|
88
117
|
```
|
|
89
118
|
|
|
90
|
-
|
|
119
|
+
Then read `pm bug list --app <appId> --status open` and
|
|
91
120
|
`pm decision list --app <appId> --limit 10`, plus
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
the selected task, linked goal, and their comments. That is the state of the
|
|
122
|
+
project—including anything a *different* agent left behind.
|
|
123
|
+
|
|
124
|
+
Before project-mutating work, decide whether the request aligns to an existing
|
|
125
|
+
open goal. If it does not, stop at conversation: explain the mismatch and ask
|
|
126
|
+
the human whether to refine/create a goal or accept a scoped exception as a PM
|
|
127
|
+
decision. Do not silently invent the outcome or begin implementation. Questions,
|
|
128
|
+
investigation, and that alignment conversation do not need a task claim.
|
|
95
129
|
|
|
96
130
|
When coordinating several efforts, begin without `--app` to see doing tasks and
|
|
97
131
|
open bugs across every co-owned project, then scope each write to the exact
|
|
@@ -101,8 +135,18 @@ goal links and comments rather than sharing a working tree or status document.
|
|
|
101
135
|
|
|
102
136
|
**While you build:**
|
|
103
137
|
|
|
104
|
-
-
|
|
105
|
-
|
|
138
|
+
- Propose work in Backlog. A human owner or `pm.plan` agent reviews/refines it,
|
|
139
|
+
links it to an open same-project goal (or accepted alignment decision), adds
|
|
140
|
+
an actionable description and acceptance criteria, then runs `pm task ready
|
|
141
|
+
<id> --expected-revision <n>`. The stored column is still `todo` for API
|
|
142
|
+
compatibility, but every product surface calls it Ready.
|
|
143
|
+
- An agent starts only with `pm task claim <id> --expected-revision <n>`. The
|
|
144
|
+
compare-and-set claim assigns the authenticated principal and moves the task
|
|
145
|
+
to Doing. Never use `pm task set --column doing` to bypass it.
|
|
146
|
+
- Use one claimed task and one owned worktree/branch. If you must stop before
|
|
147
|
+
review, run `pm task release <id> --expected-revision <n>` and comment with
|
|
148
|
+
the recovery point. Move to Review when evidence is ready; mark Done only
|
|
149
|
+
after the acceptance criteria pass.
|
|
106
150
|
- Record a decision the moment you make it, with what it rules out:
|
|
107
151
|
`pm decision add --app <appId> --title "Bun over tsx for the worker build"
|
|
108
152
|
--body "…"`. This is the single highest-value thing you can do here.
|
|
@@ -113,6 +157,90 @@ goal links and comments rather than sharing a working tree or status document.
|
|
|
113
157
|
`pm goal add --app <appId> --title "Checkout survives a retry storm" --proof
|
|
114
158
|
"test/checkout-retry.test.ts"`. Mark it met only when that proof passes.
|
|
115
159
|
|
|
160
|
+
## Referencing PM records in Discussion
|
|
161
|
+
|
|
162
|
+
Discussion markup uses stable typed references. Prefer it over pasting a title
|
|
163
|
+
that can be renamed:
|
|
164
|
+
|
|
165
|
+
```cmd
|
|
166
|
+
npx @odla-ai/cli pm task ref <task-id>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Paste the returned markup into `--markup`, alongside other references:
|
|
170
|
+
|
|
171
|
+
```cmd
|
|
172
|
+
npx @odla-ai/cli discuss post --app <appId> --subject "Ready for review" --markup "Review @[Checkout retries](pm:task/<task-id>) for @[Retry safety](pm:goal/<goal-id>)."
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The same copied `pm:*` markup works in an item's own PM comment. It is stored as
|
|
176
|
+
a structured reference, rendered as a PM chip, and printed as markup again by
|
|
177
|
+
the `comments` command:
|
|
178
|
+
|
|
179
|
+
```cmd
|
|
180
|
+
npx @odla-ai/cli pm task comment <task-id> --body "Blocked by @[Retry safety](pm:goal/<goal-id>)."
|
|
181
|
+
npx @odla-ai/cli pm task comments <task-id>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Use `pm:task`, `pm:goal`, `pm:decision`, `pm:bug`, and `pm:runbook`. The message
|
|
185
|
+
is communication; the referenced PM row remains the lifecycle authority.
|
|
186
|
+
|
|
187
|
+
In Studio, open any PM item and choose **Discuss** to open the owning project's
|
|
188
|
+
Discussion composer with the same stable reference already inserted. The draft
|
|
189
|
+
is retained in the URL across reload/back navigation but is not a write: review,
|
|
190
|
+
edit, and explicitly post it, or cancel to discard the route draft. This bridge
|
|
191
|
+
does not create a canonical one-topic-per-item stream; PM-attached comments and
|
|
192
|
+
general project Discussion still have independent capability checks and watches.
|
|
193
|
+
|
|
194
|
+
## Credentials and worktrees
|
|
195
|
+
|
|
196
|
+
A repository-local `.odla/dev-token.json` is not shared by linked worktrees.
|
|
197
|
+
For work that must run from several worktrees or another project, save a named,
|
|
198
|
+
non-secret operator context and select it explicitly:
|
|
199
|
+
|
|
200
|
+
```cmd
|
|
201
|
+
npx @odla-ai/cli context save delivery --platform https://odla.ai --app <appId>
|
|
202
|
+
npx @odla-ai/cli context show --context delivery
|
|
203
|
+
npx @odla-ai/cli pm next --context delivery
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The selected profile uses a user-level private credential cache instead of the
|
|
207
|
+
checkout-local cache. Credentials still expire. During the next handshake,
|
|
208
|
+
reusing the same immutable, human-approved project handle reconnects the new
|
|
209
|
+
credential to the existing agent principal. Follow
|
|
210
|
+
[`agent-identity.md`](./agent-identity.md): collection atomically retires the
|
|
211
|
+
older collected ordinary-handshake credential and replaces the principal's
|
|
212
|
+
manager-issued grants with the newly reviewed exact-project set. Approval alone
|
|
213
|
+
does neither, so a failed collection leaves current access intact. Deliberate
|
|
214
|
+
manual/scoped credentials still require explicit inventory review.
|
|
215
|
+
|
|
216
|
+
## State-change delivery
|
|
217
|
+
|
|
218
|
+
Every goal/task/decision/bug create/update/delete appends an immutable event
|
|
219
|
+
snapshot in the same transaction. Consume the exact-project stream with:
|
|
220
|
+
|
|
221
|
+
```cmd
|
|
222
|
+
npx @odla-ai/cli pm watch --app <appId> --jsonl
|
|
223
|
+
npx @odla-ai/cli pm watch --app <appId> --cursor <cursor> --entity task --state ready --self <principal-id> --jsonl
|
|
224
|
+
npx @odla-ai/cli pm watch --app <appId> --cursor <cursor> --entity task --action comment.created --self <principal-id> --jsonl
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The first call establishes a checkpoint and intentionally does not replay old
|
|
228
|
+
activity. Persist `checkpoint` records; delivery is at least once, so deduplicate
|
|
229
|
+
by stable `eventId`. A `checkpoint_required` status means retention/restore made
|
|
230
|
+
the cursor stale: re-read `pm next` and the active task, then establish a fresh
|
|
231
|
+
checkpoint. Filters consume nonmatching events, so a saved cursor belongs to one
|
|
232
|
+
filter policy.
|
|
233
|
+
|
|
234
|
+
`pm watch` covers PM lifecycle rows plus comments attached to active goals,
|
|
235
|
+
tasks, decisions, and bugs. It deliberately does not copy general project chat:
|
|
236
|
+
`discuss watch` still carries ordinary topics and mentions under the independent
|
|
237
|
+
Discussion capability. They are not yet one canonical topic/stream. Never infer
|
|
238
|
+
authority to start from either notification alone: re-read the Ready row and win
|
|
239
|
+
the atomic claim at its current revision.
|
|
240
|
+
|
|
241
|
+
The focused start/claim/recovery procedure is also available in
|
|
242
|
+
[`pm-work-intake.md`](./pm-work-intake.md).
|
|
243
|
+
|
|
116
244
|
**Never** put a secret, a token, or a credential in a title, body, description,
|
|
117
245
|
or comment. PM items are shared with every co-owner of the app.
|
|
118
246
|
|
|
@@ -79,12 +79,13 @@ re-run `calendar connect`.
|
|
|
79
79
|
## @odla-ai/ai — inference (Claude / GPT / Gemini)
|
|
80
80
|
|
|
81
81
|
```ts
|
|
82
|
-
const { ai } = await initFromPlatform({ platform, appId, env, db });
|
|
83
|
-
await ai.chat({ messages }); //
|
|
82
|
+
const { ai } = await initFromPlatform({ platform, appId, env, appKey, db });
|
|
83
|
+
await ai.chat({ messages, maxTokens: 512 }); // approved hosted model; db supports BYOK fallback
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
No
|
|
87
|
-
|
|
86
|
+
No provider key in your code or env. Hosted AI uses the app's existing backend
|
|
87
|
+
key and central cost attribution; `--ai-provider` explicitly opts a new config
|
|
88
|
+
into BYOK.
|
|
88
89
|
|
|
89
90
|
## @odla-ai/crm — records, pipelines, follow-ups, and contactability
|
|
90
91
|
|
|
@@ -51,7 +51,7 @@ Resolve `appId` from `odla.config.mjs`; do not guess it from a repository name,
|
|
|
51
51
|
deployment, old branch, or conversation.
|
|
52
52
|
|
|
53
53
|
```cmd
|
|
54
|
-
npx @odla-ai/cli pm
|
|
54
|
+
npx @odla-ai/cli pm next --app <appId>
|
|
55
55
|
npx @odla-ai/cli pm bug list --app <appId> --status open
|
|
56
56
|
npx @odla-ai/cli pm decision list --app <appId> --limit 20
|
|
57
57
|
npx @odla-ai/cli pm goal list --app <appId> --status open
|
|
@@ -63,9 +63,15 @@ being tested. If PM and the working tree disagree, stop, investigate, and
|
|
|
63
63
|
record the resolution as a decision or comment; do not silently pick whichever
|
|
64
64
|
is more convenient.
|
|
65
65
|
|
|
66
|
+
If the requested migration work does not align to an open goal, discuss it with
|
|
67
|
+
the human before implementing. Refine the phase task with a concrete
|
|
68
|
+
description and acceptance criteria, mark the reviewed revision Ready, and use
|
|
69
|
+
the atomic claim operation before creating its worktree. On interruption,
|
|
70
|
+
release the claim with the latest revision and comment with the recovery point.
|
|
71
|
+
|
|
66
72
|
## Update at every gate
|
|
67
73
|
|
|
68
|
-
-
|
|
74
|
+
- Mark the refined phase/track Ready, then atomically claim it when work starts.
|
|
69
75
|
- Comment with the exact verification command, result, source commit, candidate
|
|
70
76
|
deployment version, and rollback checkpoint.
|
|
71
77
|
- Record an intentional contract or product delta as a decision.
|