You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 9ccfcb4
Browse filesBrowse the repository at this point in the historyBrowse files
feat: workspace review — skill publish waits for the owner, review status, decision notices, served-version skill sync (#1685)
* feat: workspace review — skill publish waits for the owner, review status, decision notices, your pending rules
- `skill publish`: submits the skill to the linked workspace (`POST /datamates/{id}/reviews`) and reports the server's answer: published, sent for review, already waiting, or already approved; a member is told before upload when the owner has review off; older backends fall back to the previous attach; `--json`; every failure exits non-zero
- `skill-sync`: reads skill detail and files with `datamate_id`, so a contributed skill arrives at its approved version (or, for its author, the waiting one); detects changes by `revision`, falling back to `updated_at`
- `altimate-code workspace review status [--json]`: your submissions, their state and the reviewer's reason; reads only, starts nothing
- Decision notices for your skill and knowledge submissions: recorded per account and workspace outside the project, kept (the 50 most recent) and replayed by the TUI like rule notices, so one is never lost when no client is listening
- Your own pending rules (`my_pending` from the rules pull) reach your sessions under "Your rules pending review"; a pending edit shows its proposed wording to you in place of the approved rule; same scope, credential and kill-switch checks as team rules
- Server text passes through `printable` before reaching the terminal
- Docs: skills, CLI usage, learn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — skill sync downloads one version, publish finds rejected skills, CLI source
- `skill-sync`: the detail and every file read carry the listed `revision`; a mismatch (including a 409 `revision_changed`) discards that skill's whole download and the next sync retries, so a project never holds files from two versions
- A previous copy is kept over a failed download only while it is the version the workspace still serves (or was synced without a revision, from an older server); a copy of a version no longer served — a rejected or replaced one — is removed, even when every skill failed, and on an abandoned run
- `skill publish --replace` finds your existing skill through your own skills (`GET /skills?mine=true`), so a skill whose first submission was rejected is found; it still refuses a same-name skill attached only to another workspace
- Submissions from `skill publish` are recorded as from the CLI (`source: "cli"`)
- Docs: CLI usage, learn, skills
Note: workspace knowledge search is scoped by the engine that calls the knowledge query, outside this repository; it already receives the workspace id at start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — skill sync withdraws what the server says is no longer served, serialised across processes
From a second three-model review of the whole feature:
- A copy is withdrawn when the server has said its version is not served: the successful list names another revision, a read is refused with 409 `revision_changed` naming another one, or the list no longer names a skill synced from a review-aware server (it recorded a revision). This holds even when every other download fails and on an abandoned run; a plain failure (network, 401/403, 5xx) still keeps a copy the server has not contradicted
- The snapshot swap and the withdrawal on an abandoned run take the same cross-process `Flock` lock, and a withdrawal removes only a copy still identical to the one this run judged obsolete, so a newer copy another process published is kept
- A detail that answers for another revision raises the same coded `revision_changed` as the server's 409
- Docs: CLI usage
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — one credential per publish, sync never undoes a newer snapshot, notices scoped to their project
Publish
- The whole publish (identity, review summary, upload, submission, attach, ownership checks) uses one captured
credential; review client calls require it.
- A member whose server turns out to have no review keeps the upload and is told the submission failed, instead of
falling back to an owner-only attach that takes the upload back.
- A skill detail without a readable `attached_datamate_ids` fails rather than replacing the attachment set.
- `skill publish --json` reports failures before the publish (opening the project, reading skills) as JSON, once.
Skill sync
- Every removal of the live snapshot takes the cross-process snapshot lock.
- A swap or an empty-list removal goes ahead only while the live manifest is still the one the run read; a superseded
run keeps the newer snapshot and still withdraws what its own read said is no longer served.
- A copy recorded with a revision is kept on a failed download when the list names no revision.
Review notices
- A list with unreadable rows, a page short of its total, or paging without counts never lets a pending request go;
a server that ignores `page` stops after the repeat.
- Replay never waits on the network: an unknown account is looked up in the background; a link read under another
credential returns nothing.
- The TUI handles rules events of its own project only; an unknown decision status still shows a notice.
- `workspace review status` resolves the link like `workspace status` (server revalidation, unlink, rebind).
Rules
- A pending edit keeps the pin of the rule it replaces; a pending proposal whose paths change rebuilds the session.
- Pending proposals left out of a pull (unreadable or failing the lint) are reported in the sync status.
- The learning-setting response and `learn status` read review notices for the session directory.
Docs state which decisions are noticed, the first-replay exception, and what the sync and status command guarantee.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — pending rules stay pending in plugin sessions, an abandoned sync withdraws replaced copies, notices reach every linked project
Plugin host sessions (after merging main, which added them)
- Session start gives what sync vouches for, as an altimate-code session does: the person's own pending proposals
carry `review: "pending"` in `Start.rules` and are listed under their own heading, never under "approved by the
workspace owner"; a pending edit no longer shows as approved wording. The no-session fallback uses the same set.
Skill sync
- A copy whose listed revision moved on is withdrawn when the run is abandoned or superseded before its swap, even
when its replacement downloaded fine.
- The liveness check also compares the "workspace has no skills" record, so a run that started with no snapshot
cannot bring skills back after another run removed them as empty.
- A previous workspace's or account's manifest is never used to withdraw; withdrawals report the sync as changed.
Review notices
- A server or tenant without review is asked again only after 6 hours, and its 404 is not reported as an API error.
- A pending request past the page cap is looked up by id (up to 10 per poll), so its decision is still noticed.
- Stored notices follow the IDE's pin for the tree, from what is on hand; every kept decision is replayed.
Commands
- `skill publish` captures the credential before resolving the link and stops if the sign-in changed; signed out is
said as such. Error text is made printable; a failure after a written result still exits non-zero.
- `workspace review status` lists with the credential the link was resolved for.
- The TUI's fallback notice status is made printable.
Docs: a notice is shown once in each project linked to the workspace; the poll's cost is stated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — notice lookups let go of removed requests and rotate, an accepted submission never fails on an unknown row shape
- Past the list cap, a pending request the server answers 404 for is let go, and one whose lookup fails moves behind
the others, so a few failures never take every lookup.
- `skill publish` keeps an accepted submission when the server's row has a status or change this version does not
know.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/docs/configure/learn.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -205,7 +205,7 @@ The card never blocks the input: keep typing, and answer it when you are ready.
205
205
206
206
**Where they live.** Approved team rules are mirrored into the `workspace-rules` store (`.altimate-code/learn/workspace-rules/`), which is git-ignored and written only by sync: the name is reserved for it, and a store you create needs another `--name`. Everything else sync keeps (proposals waiting to be sent, your review notices, dismissed topics, your learning choice) is your rules state for the project, kept outside it in your own state directory (`$XDG_STATE_HOME/altimate-code/workspace-rules/`, usually `~/.local/state/altimate-code/workspace-rules/`, one file per project folder). Team rules are delivered from your rules state, and only while you are signed in as the account that pulled them: the project's `workspace-rules` copy is never trusted on its own, so a copy that came with a branch or a merge is not delivered. Your other stores, including one named `team`, are not touched. Team rules stop being delivered when you sign out or sign in as someone else (at once), when the project is unlinked, when the workspace refuses access, and while workspaces are turned off (`ALTIMATE_DISABLE_WORKSPACE`); they come back with the next sync.
207
207
208
-
**After review.** Approved rules reach new sessions, and new requests and files in running ones, within a few minutes (a pull at session start and every 5 minutes; `/rules` → Sync now, or `altimate-code learn sync`). A session keeps the wording it was already shown. You see a notice when the owner approves or rejects your rule, with the reason. Usage is reported back to the workspace: how many sessions a rule was applied in, and how often you corrected the agent on its topic after it was shown ("corrected again").
208
+
**After review.** Approved rules reach new sessions, and new requests and files in running ones, within a few minutes (a pull at session start and every 5 minutes; `/rules` → Sync now, or `altimate-code learn sync`). A session keeps the wording it was already shown. You see a notice when the owner approves or rejects your rule, with the reason. Your own proposals still waiting for review are delivered to you, and only you, from the same pull: a new rule under a "Your rules pending review" heading after the team rules, and a proposed edit in place of the rule it would replace (a proposed retirement changes nothing until it is approved). They follow the team rules' conditions (learning on, workspaces on, signed in as the account that pulled them, the same workspace and repository), and once a proposal is approved or rejected the next pull delivers what the workspace holds then. Proposals still queued on this machine and not yet sent are not delivered; they arrive with the pull after they are sent, usually the same sync. Usage is reported back to the workspace: how many sessions a rule was applied in, and how often you corrected the agent on its topic after it was shown ("corrected again").
209
209
210
210
**Learning on or off.** In order: the learning kill switch (`learn.enabled`, `ALTIMATE_LEARN`), `ALTIMATE_LEARN_CAPTURE`, a `learn.capture` your organization sets (managed config, MDM, the account's config, `OPENCODE_CONFIG_CONTENT`, `OPENCODE_CONFIG_DIR` or the home `~/.altimate-code` config; shown as "organization policy"), your `/rules` → "Turn learning on/off for me" choice, `learn.capture` (`learn enable` / `learn disable`), then the workspace's "Learn from sessions". The `/rules` choice is yours alone: it is kept in your own rules state for the project, outside it, not in the project config, so it never reaches a teammate through a commit ("Follow the workspace setting again" clears it). It takes effect right away. Approved rules are delivered either way.
211
211
@@ -668,7 +668,7 @@ Full setup, arms, and caveats are in the research notes in the repository under
668
668
-**Conflict detection sees backticked identifiers.** Two rules that contradict each other in prose, with no shared identifier in backticks, depend on the reflector and the replacement step.
669
669
-**Reflection quality depends on the model.** In our test a weaker reflector needed the replacement step to reach the same result as a stronger one. You still review every candidate.
670
670
-**Review import is GitHub only.** GitLab, Bitbucket, and other hosts are not supported. It reads merged PRs, not open ones.
671
-
-**Local rules are shared by hand.** In a project linked to a workspace, team rules are proposed and reviewed per rule (see [Workspace rules](#workspace-rules)). Rules in the project's local stores under `.altimate-code/learn/` are not: `promote --publish` exports them as a single-file workspace skill. Publishing a name that another checkout already published is refused unless you pass `--replace`, which only updates a skill you own. You can also commit the rules: learn creates `.altimate-code/learn/.gitignore`, which ignores everything except each store's `approved.json`, and delivery reads a committed `approved.json` in any checkout.
671
+
-**Local rules are shared by hand.** In a project linked to a workspace, team rules are proposed and reviewed per rule (see [Workspace rules](#workspace-rules)). Rules in the project's local stores under `.altimate-code/learn/` are not: `promote --publish` exports them as a single-file workspace skill. Publishing a name that another checkout already published is refused unless you pass `--replace`, which only updates a skill you own: it is looked up among your own skills, so it also finds one that is attached to no workspace (for example after its first review request was rejected), but not one attached only to other workspaces. You can also commit the rules: learn creates `.altimate-code/learn/.gitignore`, which ignores everything except each store's `approved.json`, and delivery reads a committed `approved.json` in any checkout.
672
672
-**One rule set per `--name`.** Delivery reads every store in the project that has an `approved.json`.
673
673
-**Keyword retrieval can over-apply a rule.** A rule scoped to one kind of file can be retrieved for a request elsewhere that uses the same words, and the agent sometimes follows it there. In our benchmark a staging-model money rule was applied to an analysis that had to keep integer cents in 1 of 6 runs, in three of the retrieval arms. Showing the rule's scope did not remove it. Write the scope into the rule's path triggers.
674
674
-**Benchmarks are on dbt tasks, with small samples.** The results show direction, not exact lift for your repository.
altimate-code skill publish my-tool # upload every file in the skill directory; re-run to update
198
+
altimate-code skill publish my-tool --json # the same, with the result (and the server's review status) as JSON
199
+
200
+
# Your review requests on the linked workspace
201
+
altimate-code workspace review status # changes nothing on the server; --json for scripts
198
202
```
199
203
204
+
**Workspace review.** When the workspace service supports review, `skill publish` uploads the skill to your own skills and then submits it to the linked workspace, and what it prints comes from the service's answer:
205
+
206
+
-`Published "<name>" to "<workspace>"`: you own the workspace, so the skill is attached directly.
207
+
-`Sent "<name>" for review to <owner>`: you are a member of a workspace whose owner turned review on. The team gets the skill once the owner approves it in the Altimate web app; until then only you get your pending version. Approving and rejecting happen only in the web app.
208
+
-`Already waiting for review` or `Already approved`: the same content was already submitted or approved, so nothing new was sent.
209
+
210
+
Requests sent from the CLI are recorded as such in the request's history. What the team gets is the exact version that was approved: editing the skill afterwards changes nothing for them until you run `skill publish` again, which submits the new version as an update. A member publishing to a workspace whose owner has review off is refused before anything is uploaded. If the skill uploads but cannot be sent (offline, an expired sign-in, too many open requests), the command says so and exits non-zero; running it again updates the uploaded skill and submits it. Against a workspace service without review, `skill publish` attaches the skill directly as before, which only the workspace owner can do. With `--json`, the output carries `ok`, the upload (`action`, `public_id`, `files`, `bytes`, `workspace_id`, `workspace_name`) and `review` with the service's `status`, `attached_directly`, `duplicate`, `owner_name` and `contribution` (`null` without review); every failure exits non-zero with `{"ok": false, "error": ...}`.
211
+
212
+
When the owner approves or rejects one of your requests that this client has seen pending (submitted from it, or listed by an earlier check), the TUI shows a notice once in each project linked to that workspace (with the reason for a rejection). Each altimate-code process with a linked project open checks at start and every 5 minutes (a server without review is asked again only after 6 hours) and keeps the 50 most recent decisions in your own state directory, so a decision that arrives while the TUI is closed or disconnected is shown when it next starts (as rule review notices are). The first time a TUI opens a project, decisions already kept are recorded without a notice; `workspace review status` lists them. `altimate-code workspace review status` lists your requests on the linked workspace (skills and knowledge bases): kind, name, status, whether it is new or an update, the reviewer and their reason, and `expired` for a request waiting longer than 14 days (it can still be approved).
213
+
200
214
`skill publish` sends the whole skill directory, not just `SKILL.md`, so keep secrets out of it. A built-in filter skips known file and directory names — `.env*`, `.git`, `id_rsa`, `*.pem`, `*.key`, `*.p12`, `.npmrc`/`.netrc`, `credentials.json`, `secrets.*`, `.ssh`/`.aws`, editor swap files — but it matches names only and never scans file contents, so a token inside `config.yaml` or a key named `server.crt` would still be uploaded. Built-in skills, global skills and skills the workspace itself sent you cannot be published — including the copies the VS Code / Cursor extension delivers into `.claude/skills/` and `.agents/skills/`, which carry an `.altimate-managed.json` marker.
Copy file name to clipboardExpand all lines: docs/docs/usage/cli.md
+4-1Lines changed: 4 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,12 +60,15 @@ With workspaces on:
60
60
-`altimate-code link --workspace <name|id>` links to an existing workspace (an id is matched before a name), and `altimate-code link --create [name]` creates one (named after the repo by default) and links to it. Neither prompts. If the project is already linked to a different workspace they refuse unless `--yes` is passed. Running `--create` again when the project is already linked to a workspace of that name creates nothing, so it is safe in a devcontainer's setup command; if another workspace already has that name it refuses and names its id, unless `--allow-duplicate` is passed. Linking to the workspace the project is already linked to confirms that link on this machine, which a fresh clone needs before `workspace sync` sends its memory.
61
61
-`altimate-code workspace list [--json]` lists the workspaces your account can link to, with their ids, for `link --workspace`.
62
62
-`altimate-code workspace status [--json]` shows the linked workspace and, when known, how many saved memories have not reached it and when skills last synced.
63
+
-`altimate-code workspace review status [--json]` lists your own review requests on the linked workspace (skills from `skill publish`, and knowledge bases you submitted in the web app): kind, name, status, new or update, the reviewer and their reason, and whether a pending request has waited past 14 days (`expired`; it can still be approved). It changes nothing on the server: it does not open the project, so it starts no sync (checking the link may refresh this machine's record of it, as `workspace status` does). Approving and rejecting happen in the Altimate web app.
63
64
-`altimate-code workspace refresh` pulls the workspace's skills (memory is loaded by the next session started in the project); `altimate-code workspace sync` sends memory the workspace has not received; `altimate-code workspace unlink [--yes]` detaches the project (`--yes` is required without a terminal).
64
65
- These commands accept `--directory`. Exit codes: `0` done, `1` failed (including when the workspace service could not be reached), `2` a request to change (not signed in, a re-link or unlink without `--yes` and no terminal to confirm on, or a `sync` to a link not yet confirmed on this machine), `3` the project is not linked. With `--json`, `ok` is `true` exactly when the exit code is `0`.
65
66
-`/workspace` in the TUI opens a menu: **Get started** shows what the workspace provides and prompts to try (choosing one puts it in the prompt without sending it; after you link from the TUI, the confirmation shows the same summary and prompts), **Refresh** pulls the workspace's skills and memory into this project, **Sync** re-sends local memory the workspace never received, **Open in browser** (when a web URL is available) shows the workspace on the web, **Switch workspace** relinks the project, **Unlink** detaches it. In a project that is not linked yet, it offers **Link to a workspace** instead.
66
67
-`/integrations` in the TUI opens the workspace's integration status directly (the same view as `/workspace` → Status). In a project that is not linked it offers the link, and when the workspace engine is missing or too old it offers the install and says which.
67
68
- In a project linked to a workspace, integrations come only from the workspace's engine, so the `datamate_manager` tool is not offered there and refuses to run. `datamate-*` MCP servers already in the config still load, and a one-time notice names the file they are in; the config is not edited.
68
-
-`altimate-code skill publish <name>` uploads a project skill to the linked workspace; see [Skills](../configure/skills.md#cli-commands).
69
+
-`altimate-code skill publish <name>` uploads a project skill to the linked workspace, attached directly for the workspace owner and sent for the owner's review for a member when the owner has turned review on; see [Skills](../configure/skills.md#cli-commands).
70
+
- When the owner approves or rejects one of your skill or knowledge base requests that altimate-code has seen pending (submitted from it, or listed by an earlier check), the TUI shows a notice once in each project linked to that workspace, with the reason for a rejection. Every altimate-code process that opens a linked project checks at start and every 5 minutes while workspaces are on and you are signed in: it lists your own requests on the workspace (up to 10 pages of 50); a server without review is asked again only after 6 hours. The decision is kept per account and workspace in your own state directory (`$XDG_STATE_HOME/altimate-code/workspace-reviews/`, the 50 most recent), so a TUI that was closed or disconnected when it arrived shows it when it next starts. The first time a TUI opens a project, decisions already kept are recorded without a notice; `altimate-code workspace review status` lists them.
71
+
- Workspace skills are synced at the version the workspace serves you: the approved version, or your own pending version of a skill you submitted. The next sync follows what the workspace serves: a skill whose first submission is rejected, or that is detached from the workspace, is removed from the project; when an update to an approved skill is rejected or replaced, the skill stays at its approved version. Each skill is downloaded as one version: if it is approved or rejected while its files are being read, nothing of it is installed from that sync and it is fetched again on the next one. When a download fails, the copy already in the project is kept only if it is still the version the workspace serves, as far as the server has said (its list, or a read refused because the version just changed), or if neither the copy nor the list names a version (a copy synced before revisions, or an older server), in which case it is kept until the server says otherwise; a copy of a version it no longer serves (for example your rejected pending version), or of a skill it no longer lists, is removed until the download succeeds, even when no other skill could be downloaded. Two processes syncing the same project take turns: a sync never replaces or removes a snapshot another process installed after it started, and the next sync starts from the newer one.
69
72
- When the linked workspace has knowledge, the agent is told to check it for best practices and team conventions before answering, without you having to mention the knowledge base.
70
73
- In an ordinary session the agent is told every turn which workspace the project is linked to — or that none is, or that the link could not be verified just now. In an extension-pinned session it is told the pinned workspace instead, and that it differs from the project's own link. Either way "which workspace am I in?" has an answer, and the agent is told not to confuse it with a Databricks workspace or an IDE workspace folder.
71
74
- When `altimate-code serve` is launched by the VS Code / Cursor extension, the workspace selected in the extension's panel governs that session's skills, memory and (unless `--integrations local` is set) warehouse tool routing, taking priority over whatever the project is linked to on the backend, and is scoped to the folder it was launched for. A pin is fixed for the life of the `serve` process, so the extension relaunches `serve` when the selection changes; nothing updates a running one.
0 commit comments