orboto 0.173.0
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 +62 -0
- package/bin/orboto.mjs +26 -0
- package/dist/DOCS-WIKI.md +52 -0
- package/dist/REFERENCE.md +149 -0
- package/dist/SKILL.md +476 -0
- package/dist/orboto.mjs +5766 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# orboto CLI
|
|
2
|
+
|
|
3
|
+
Drive [orboto](https://orboto.io) - tickets, projects, docs, time
|
|
4
|
+
tracking, agent coordination - from any shell or AI agent harness.
|
|
5
|
+
Zero dependencies, one file, made for automation: every command prints
|
|
6
|
+
JSON you can pipe through `jq`/`grep`, so only the bytes you need enter
|
|
7
|
+
an agent's context.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx orboto whoami
|
|
11
|
+
npx orboto ticket ORB-42 --full
|
|
12
|
+
npx orboto claim ORB-42
|
|
13
|
+
npx orboto query "project = ORB AND status = 'To Do'"
|
|
14
|
+
npx orboto agent-notify runner@agents.internal "wakeup" --project ORB
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run `orboto help` for the full command list. The complete operation
|
|
18
|
+
reference ships inside the package (`dist/REFERENCE.md`, doc/wiki
|
|
19
|
+
operations in `dist/DOCS-WIKI.md`).
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g orboto # or: npx orboto <cmd>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Credentials
|
|
28
|
+
|
|
29
|
+
The CLI talks to your orboto instance with a service-account API key
|
|
30
|
+
(`orb_...`, minted under Admin -> Users -> API keys, or via the OAuth
|
|
31
|
+
act-as flow for bot identities). Resolution order:
|
|
32
|
+
|
|
33
|
+
1. Environment: `ORBOTO_BASE_URL` (e.g. `https://your-orboto/api`) and
|
|
34
|
+
`ORBOTO_TOKEN`.
|
|
35
|
+
2. `./.orboto.env` in the working directory (per-repo).
|
|
36
|
+
3. `~/.orboto/env` (user-global).
|
|
37
|
+
|
|
38
|
+
The env files use plain `KEY=value` lines:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
ORBOTO_BASE_URL=https://your-orboto/api
|
|
42
|
+
ORBOTO_TOKEN=orb_xxxxxxxx
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## For AI agents
|
|
46
|
+
|
|
47
|
+
This CLI is the recommended integration for agent harnesses without MCP
|
|
48
|
+
support (and the context-cheapest one everywhere else): no standing tool
|
|
49
|
+
manifest, docs load lazily, output is filterable before it enters
|
|
50
|
+
context. Agent-facing conventions (claim -> commit -> close loop, agent
|
|
51
|
+
inbox, work sessions) are described in the bundled `dist/SKILL.md` and
|
|
52
|
+
`dist/REFERENCE.md`.
|
|
53
|
+
|
|
54
|
+
## Development
|
|
55
|
+
|
|
56
|
+
In the orboto monorepo the binary runs the in-repo script directly
|
|
57
|
+
(`skills/orboto/scripts/orboto.mjs` stays the single source of truth);
|
|
58
|
+
`npm pack` bundles it into `dist/` for standalone installs.
|
|
59
|
+
|
|
60
|
+
Publishing (operator): `cd packages/cli && npm publish` - the unscoped
|
|
61
|
+
`orboto` name is published from the orboto npm account/org; versions are
|
|
62
|
+
bumped by `scripts/release.mjs` in lockstep with the platform.
|
package/bin/orboto.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* orboto CLI entry point (ORB-1740).
|
|
4
|
+
*
|
|
5
|
+
* Resolution order:
|
|
6
|
+
* 1. dist/orboto.mjs - the copy `prepack` bundles into the published
|
|
7
|
+
* package (npm/npx installs run this).
|
|
8
|
+
* 2. skills/orboto/scripts/orboto.mjs - the in-repo single source of
|
|
9
|
+
* truth (running from a monorepo checkout / pnpm workspace).
|
|
10
|
+
*
|
|
11
|
+
* The script itself stays in skills/orboto so the skill-delivery routes
|
|
12
|
+
* (routes/skills.ts, agent-bootstrap.ts) keep serving the identical file;
|
|
13
|
+
* this shim only decides WHICH copy runs.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const bundled = new URL('../dist/orboto.mjs', import.meta.url);
|
|
19
|
+
const dev = new URL('../../../skills/orboto/scripts/orboto.mjs', import.meta.url);
|
|
20
|
+
|
|
21
|
+
const target = existsSync(fileURLToPath(bundled)) ? bundled : dev;
|
|
22
|
+
if (!existsSync(fileURLToPath(target))) {
|
|
23
|
+
console.error('orboto: CLI script not found (neither bundled dist/ nor the in-repo skill copy). Reinstall the package.');
|
|
24
|
+
process.exit(2);
|
|
25
|
+
}
|
|
26
|
+
await import(target.href);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# orboto skill - Docs & Wiki
|
|
2
|
+
|
|
3
|
+
Doc spaces, docs, revisions, comments, attachments, exports, the wiki curation commands, and URL/file ingest - split out of `SKILL.md` for progressive disclosure (ORB-1333). Read `SKILL.md` first for the workflow and safety rules, and `REFERENCE.md` for the non-doc operation catalogue. These rows are part of the same operation-reference table; the four-way-sync contract applies to them exactly as it does in `REFERENCE.md`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Doc & wiki operations
|
|
8
|
+
|
|
9
|
+
| Task | Shortcut or raw call | Notes |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Search docs (snippets) | `search-docs "<query>" [--project=KEY] [--space=<spaceId>] [--limit=20]` | **Snippet-level** doc search (ORB-1340): each hit returns a highlighted snippet (`<mark>` around matches) + the nearest markdown heading path (section anchor) + line offset - WITHOUT the full doc body. Use it to LOCATE a passage, then change it with `edit-doc`. ACL-filtered in SQL. MCP: `orboto_search_docs`; also in the in-app AI chat. Prefer over `search --types=doc` when you need the matching passage, not just the doc title. |
|
|
12
|
+
| Ask the docs | `ask-docs <question> [--space=<id>] [--limit=5]` | RAG Q&A over wiki docs; returns answer + numbered citations. ACL-safe. **Requires `configured=true` AND `embeddingsConfigured=true` on the workspace** - call `ai-status` first if unsure. |
|
|
13
|
+
| Import URL as doc | `ingest-url <url> --space=<space-id> [--parent=<doc-id>]` | Fetch a public URL, extract main article via Readability, convert to Markdown, create a new doc. SSRF-safe. Works without AI; the doc only becomes semantically searchable via `ask-docs` once embeddings are configured on the workspace. |
|
|
14
|
+
| Import file as doc | `ingest-file <path> --space=<space-id> [--parent=<doc-id>]` | Upload a local PDF / .docx / .md / .txt file and create a new doc from its contents. 25 MB cap. Works without AI; same RAG-search caveat as `ingest-url`. |
|
|
15
|
+
| List doc spaces | `list-spaces` | Workspace-wide spaces (global + project-scoped) the caller can see. Returns name + scope + UUID per row. |
|
|
16
|
+
| List docs in space | `list-docs <space>` | `<space>` accepts the space key (`ORB-S1`), name, or UUID (ORB-1161) - find them via `list-spaces`. Flat list of every doc in the space, rendered as an indented tree. Each row shows the doc's typeable key (`ORB-D12` / `DOC-5`, ORB-1004). Read a single page with `get /docs/by-key/<KEY>` or `get /docs/<UUID>`. |
|
|
17
|
+
| Create doc space | `create-doc-space <name> --type=global\|project [--project=<projectKey>] [--icon "📘"] [--description "..."]` | Workspace-wide (global, super-admin only) or project-scoped space. `--project` takes a project **key** (e.g. `ORB`); a raw UUID still works. Slug auto-derived from name. MCP: `orboto_create_doc_space` (`projectKey`). **Every project already has an auto-generated general space** (slug `<key>-general`, system-generated, holds the AI primer + manual notes) - `list-spaces` and reuse it for a project's docs instead of creating a duplicate; only make a new space for a genuinely separate collection. |
|
|
18
|
+
| Update doc space | `patch /spaces/:id '{"name":"…"}'` | Patch name / description / icon, plus visibility settings (`visibility`: workspace\|project_members\|restricted, `guestsVisible`, `memberIds` - manage rights required: global spaces super-admin, project spaces project:edit). `isPublic` is deprecated in favour of `guestsVisible`. Raw API - rare enough not to warrant a shortcut. Auto-generated primer spaces refuse name + slug edits. |
|
|
19
|
+
| Delete doc space | `delete /spaces/:id` | DESTRUCTIVE - cascades through every doc in the space. Refuses on auto-generated project primer spaces. |
|
|
20
|
+
| Create doc | `create-doc "<title>" --space=<space> [--parent=<docId>] [--visibility=...] [--icon "..."] (--content "..." \| --content-stdin)` | `--space` accepts the space key (`ORB-S1`), name, or UUID (ORB-1161). Plain page from supplied Markdown. Heredoc-stdin for large bodies. |
|
|
21
|
+
| Patch doc | `patch-doc <docId> [--title "..."] (--content "..." \| --content-stdin) [--parent=<id\|null>] [--visibility=...] [--icon "..."]` | Edit a page. Replaces the WHOLE content. Each title/content change auto-snapshots the previous version into revision history. For a small change to a large doc, prefer `edit-doc` (ships only the diff). |
|
|
22
|
+
| Edit doc (targeted) | `edit-doc <docId> (--old "<s>" \| --old-stdin) (--new "<s>" \| --new-stdin) [--all] [--base <revisionId>]` | Byte-precise string-replace edit (ORB-1341) - ship only the diff, not the whole doc. `oldString` must match EXACTLY ONCE unless `--all`. `--base <revisionId>` = optimistic concurrency (stale token → 409 with the current revision id). `--new ""` deletes the match. Multiline: `--old-stdin` / `--new-stdin`. Returns the new revisionId + a context window per change. MCP: `orboto_edit_doc` (+ `orboto_edit_doc_section` for heading-addressed section ops); also in the in-app AI chat. Heading-addressed section ops via the raw API: `post /docs/<id>/edits '{"sectionOps":[{"headingPath":["Setup"],"op":"replace","content":"…"}]}'`. |
|
|
23
|
+
| Delete doc | `delete-doc <docId>` | DESTRUCTIVE - removes the page from the tree. Refuses on auto-managed primer docs. |
|
|
24
|
+
| Move doc | `move-doc <docId> [--parent=<id\|null>] [--space=<spaceId>] [--order=<n>]` | Reparent, reorder, or cross-space move. At least one target field required. |
|
|
25
|
+
| Attach to doc | `attach-doc <docId> <path…> [--alt "text"] [--embed]` | Upload one or more files. Image MIMEs render as ``, others as `[alt](url)`. `--embed` appends to the doc body. |
|
|
26
|
+
| List doc attachments | `list-doc-attachments <docId>` | Newest-first with KB + MIME + stable URL. |
|
|
27
|
+
| Delete doc attachment | `delete-doc-attachment <docId> <attachmentId>` | DESTRUCTIVE - drops the row + S3 object. Doc body is not rewritten; embedded Markdown lines pointing at the deleted URL will break. |
|
|
28
|
+
| Export doc as Markdown | `export-doc-md <docId> [--out=path.md]` | Prints to stdout by default; `--out` writes the file. Emits the canonical saved body (no get-doc envelope). |
|
|
29
|
+
| Export doc as PDF | `export-doc-pdf <docId> --out=path.pdf` | `--out` required (binary). Requires PdfService configured on the deployment; otherwise 503. |
|
|
30
|
+
| List doc revisions | `doc-revisions <docId> [--limit=25] [--cursor=...]` | Newest-first revision audit trail. Cursor-paged. Bodies excluded - use `doc-revision` to fetch one. |
|
|
31
|
+
| Get doc revision | `doc-revision <docId> <revisionId>` | Full saved body + title of one revision. Use this to diff against current before restoring. |
|
|
32
|
+
| Restore doc revision | `restore-doc-revision <docId> <revisionId>` | Roll back to a saved revision. API auto-snapshots the current body first, so the restore itself is undoable. |
|
|
33
|
+
| List doc comments | `doc-comments <docId> [--limit=25] [--cursor=...]` | Threaded view with replies indented one level. Cursor-paged, oldest-first. |
|
|
34
|
+
| Post doc comment | `doc-comment <docId> "<text>" [--reply-to=<commentId>]` or `doc-comment <docId> --content-stdin` | Plain comment or reply. Heredoc for long bodies. `@mentions` fire notifications. |
|
|
35
|
+
| Resolve doc comment | `resolve-doc-comment <docId> <commentId> [--reopen]` | Folds the whole thread (always acts on the root). `--reopen` flips back to open. |
|
|
36
|
+
| Delete doc comment | `delete-doc-comment <docId> <commentId>` | DESTRUCTIVE - drops the comment + its reply subtree. Only the author or super-admin can. |
|
|
37
|
+
| Duplicate doc space | `duplicate-space <spaceId>` | Forks the space + its entire doc tree. New space name = `<source> (copy)`; parent-child relationships preserved via UUID remap. |
|
|
38
|
+
| Resolve smart-link refs | `resolve-links <type:id> [<type:id> ...]` | Batch-resolve `doc:UUID\|KEY` / `ticket:UUID\|KEY` / `milestone:UUID` / `project:UUID\|KEY` / `commit:HASH` to title + URL in one call. Tickets, projects and docs accept the human-readable key form (`doc:ORB-D12`, ORB-1004). Visibility-filtered (unresolved items list separately). Max 200 items. |
|
|
39
|
+
| List docs | `get /spaces/:id/docs` | |
|
|
40
|
+
| Create doc | `post /spaces/:id/docs` | Markdown body |
|
|
41
|
+
| Wiki: ingest URL | `wiki-ingest <url> --space=<id> [--parent=<doc-id>]` | ORB-855 - import a URL as a SOURCE doc; on an LLM-Wiki-enabled space the curation worker turns it into wiki pages (auto-apply or a pending plan per the space's applyMode). |
|
|
42
|
+
| Wiki: ask | `wiki-ask <question> [--space=<id>] [--limit=5]` | RAG Q&A over the wiki with citations. Needs `configured` + `embeddingsConfigured` (see `ai-status`). |
|
|
43
|
+
| Wiki: save answer | `wiki-save-answer "<question>" --space=<id> (--answer "<text>" \| --answer-stdin) [--title "..."]` | ORB-857 - turn a Q&A answer into a curated wiki page. Idempotent per (space, question): re-saving updates the page. |
|
|
44
|
+
| Wiki: lint | `wiki-lint <space-id>` | Run the lint pass; returns open issues (orphans, missing cross-refs, stale, unprocessed sources, + AI contradictions/undocumented) each with a suggested fix. |
|
|
45
|
+
| Wiki: plan edit | `wiki-plan <space-id> "<instruction>" [--source=<doc-id>]` | Dry-run: turns an instruction into page ops + a `planId` (15-min TTL). No writes. |
|
|
46
|
+
| Wiki: apply plan | `wiki-apply <space-id> <plan-id>` | Commit a plan atomically. 410 if expired. |
|
|
47
|
+
| Wiki: record | `wiki-record <space-id> "<instruction>" [--source=<doc-id>]` | Convenience: plan + apply in one step. Use mid-task to capture a fact without the review loop. |
|
|
48
|
+
| Wiki: append section | `wiki-append-section <doc-id> "<markdown>" \| --content-stdin` | Idempotent - re-appending identical content is a no-op (dedup on multi-ingest). |
|
|
49
|
+
| Wiki: flag stale | `wiki-flag-stale <doc-id> [--clear]` | Set / clear the passive "may be outdated" flag on a page. |
|
|
50
|
+
| Edit doc comment | `patch /docs/:id/comments/:cid '{"content":"…"}'` | ORB-933 - author or super-admin. Doc-comments have no revision history today (unlike ticket-comments), so the prior text is overwritten. |
|
|
51
|
+
|
|
52
|
+
> **Context-efficient doc edits (ORB-1339): prefer `search-docs` + `edit-doc` over `get-doc` + `patch-doc` for small changes.** The old pattern (`get /docs/<id>` to read the whole body → edit in memory → `patch-doc --content-stdin` the whole body back) transfers the full document TWICE for a one-word fix - on a large runbook that floods your context both directions. Instead: `search-docs "<distinctive phrase>"` returns just the matching snippet + its heading anchor (not the body), and `edit-doc <docId> --old "…" --new "…"` ships only the diff and returns a short context window confirming the change. Full-doc `patch-doc` is still correct for large rewrites or when you're replacing most of the page; targeted `edit-doc` is for surgical changes. `edit-doc` requires the `oldString` to match exactly once (add surrounding context to disambiguate, or `--all`), so it fails loud rather than editing the wrong occurrence. Pass `--base <revisionId>` when a concurrent editor is plausible to get optimistic-concurrency protection instead of a silent clobber.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# orboto skill - Operation reference
|
|
2
|
+
|
|
3
|
+
> ORB-1740: every command below is also available standalone via the npm package `orboto` (`npx orboto <cmd>`), no repo checkout needed - credentials via env vars, `./.orboto.env`, or `~/.orboto/env`.
|
|
4
|
+
|
|
5
|
+
The complete catalogue of `scripts/orboto.mjs` shortcuts and raw API calls, split out of `SKILL.md` for progressive disclosure (ORB-1333). Read `SKILL.md` first - it carries the workflow, the rhythm, and the safety rules. This file is the lookup table for when you know the shape you want but forgot the exact command. Doc/wiki operations live in `DOCS-WIKI.md`; daemon-mode, multi-agent coordination, the OQL deep-dive, and primer/personal-fact maintenance live in `ADVANCED.md`.
|
|
6
|
+
|
|
7
|
+
**Four-way sync (for maintainers):** when an agent-facing API capability ships or changes shape, the matching row in THIS file is one of the four surfaces to keep in step (alongside `apps/mcp/`, the wrapper shortcut, and the in-app AI-chat tool registry). See the repo `CLAUDE.md`.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Operation reference
|
|
12
|
+
|
|
13
|
+
**Pagination (raw API):** list endpoints return `{ items, nextCursor }`, not `{ data, total }`. Pass the returned `nextCursor` back as the `cursor` query param to fetch the next page; `nextCursor === null` means you reached the end. The wrapper shortcuts (`list-tickets`, `my-tickets`, `search`) walk pages transparently - this only matters when you call a raw `get /...` yourself.
|
|
14
|
+
|
|
15
|
+
| Task | Shortcut or raw call | Notes |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Who am I | `whoami` | |
|
|
18
|
+
| AI status | `ai-status` | Returns `{ configured, embeddingsConfigured, visionEnabled }`. Run this before invoking AI-gated shortcuts (see "AI-dependent operations" below). `visionEnabled` = image attachments allowed in AI calls. Anthropic-only deployments report `configured=true, embeddingsConfigured=false`. |
|
|
19
|
+
| Embedding status | `embedding-status` | Embedding pipeline diagnostic: provider/model/dims, coverage (embedded/total/**pending** per tickets/comments/docs + overall), circuit-breaker state + reason, managed-AI billing-gate state (`billingGate` - AI paused for a billing reason the workspace admin fixes in their orboto account, not a provider fault), managed-AI spend state (`spend` - included allowance used/remaining, overage mode, wallet - warn before the gate), last-embedded time. Use to diagnose stale/empty semantic search or duplicate detection (tripped breaker, stuck queue, billing gate, provider not responding). Requires `admin:ai:read`. MCP: `orboto_embedding_status`; also exposed in the in-app AI chat. |
|
|
20
|
+
| AI usage | `ai-usage [--start YYYY-MM-DD] [--end YYYY-MM-DD]` | AI consumption over a range (default last 30 days): totals (calls, tokens in/out, **errors**), per-user / per-operation / per-day breakdowns, AI-Chat slice. Use for spend / call volume / which ops run most / how many calls erroring. Aggregates only - not per-row error text. Requires `admin:ai:read`. MCP: `orboto_ai_usage`; also in the in-app AI chat. |
|
|
21
|
+
| Self-update | `self-update [--dry-run] [--force]` | Pull the matching skill bundle from the running orboto instance so this script stays in sync. Compares local `manifest.json` version against `/version`, downloads only files whose SHA256 changed, verifies post-download. Skill files are part of the user's repo - review with `git diff` on the skill directory after running. |
|
|
22
|
+
| My tickets | `my-tickets [--project ORB] [--limit N]` | Compact output: key, title, status, priority |
|
|
23
|
+
| List project tickets | `list-tickets <key> [--status todo\|…] [--parent ORB-N] [--limit N]` | Compact output with assignees. `--parent` walks an epic's sub-tickets. |
|
|
24
|
+
| List sub-tickets | `list-tickets <key> --parent ORB-42` | Children of an epic / story, project-scoped |
|
|
25
|
+
| My deadlines | `get /users/me/upcoming-deadlines` | |
|
|
26
|
+
| Free/busy | `get "/users/free-busy?userIds=<uuid,uuid>&from=YYYY-MM-DD&to=YYYY-MM-DD&granularity=day\|week"` | Batched near-term capacity per user: `status` (available/busy/overcapacity/absent/unknown) + per-bucket planned/booked/capacity/onAbsence/externalBusy minutes. `unknown` = user opted out or workspace hides it from you. Gated by `system_config.free_busy_team_visibility` (disabled → 403 for non-admins) + per-user `free_busy_visible` opt-out. Default window = next 2 weeks. MCP: `orboto_free_busy`; also in the in-app AI chat. |
|
|
27
|
+
| List projects | `get /projects` | Only ones you're a member of |
|
|
28
|
+
| Project detail | `get /projects/:id` | |
|
|
29
|
+
| Project workflow | `get /projects/:id/ticket-statuses` | Required before any `statusId` decision |
|
|
30
|
+
| Compact ticket | `ticket ORB-42` | Compact card (~400 bytes). `--full` for raw JSON. |
|
|
31
|
+
| Short-form raw GET/PATCH/DELETE | `get/patch/delete /tickets/<idOrKey>` | ORB-934 - top-level shortcut. Accepts UUID or ticket-key (`ORB-42`, case-insensitive). API resolves the project + 307-redirects to the canonical `/projects/:projectId/tickets/:id` path so every permission gate fires unchanged. Use when you only have a key/UUID and don't want to look up the project first. Returns 404 if no ticket matches. |
|
|
32
|
+
| Create ticket | `create-ticket <key> <title> [flags]` | `--type` `--priority` `--delivery-mode implementation\|docs\|review\|admin\|epic` `--milestone` `--assign` `--label` `--parent` `--due` `--private` `--description` `--attach <path>[:alt]` `--allow-language-mismatch` `--allow-duplicate --duplicate-justification "..."`. **`--delivery-mode` (ORB-1608)** - role-aware commit policy replacing the blanket one-commit-per-ticket rule; unset defaults to `epic` when `--type epic`, else `implementation`. See *The rhythm* in `SKILL.md`. **`--label` + `--assign` attach ATOMICALLY inside the create (ORB-1416)** - an unknown label or non-member assignee rolls the whole create back with a 400 (no orphan ticket); no separate attach call, no retry-into-a-duplicate. **Returns `similarWarnings` when potential duplicates exist (ORB-831)** - review and close-as-duplicate if covered. **Under high create load returns `duplicateCheckDeferred: true` (ORB-1437)** - the check ran in the background (empty `similarWarnings` is then NOT "no duplicates"); a strong match arrives as an advisory comment on the new ticket. **Hard duplicate-block (ORB-1471):** when the workspace sets `duplicate_block_threshold` and the top match meets it, the create is REFUSED with a 409 (exit 1) listing the candidates - extend one of them, or re-run with `--allow-duplicate --duplicate-justification "..."` (persisted as a comment). **Returns `languageWarning` when the ticket reads as a language different from the workspace default (ORB-890)** - consider rewriting to keep search + duplicate-detection consistent across the project; a workspace with strict enforcement REJECTS the mismatch with a 422 (errorKey `errors.tickets.language_mismatch`) - rewrite, or pass `--allow-language-mismatch`. |
|
|
33
|
+
| Check duplicates | `check-similar <projectKey> "<title>" [--description "..."] [--limit N]` | Dry-run probe - returns the candidates the create-time safety-net would warn about plus a `safe to create` / `Possible related tickets` / `HIGH-SIMILARITY MATCH FOUND` recommendation. Run this before any new-ticket title that feels close to existing work. |
|
|
34
|
+
| Create milestone | `create-milestone <projectKey> <name> [--start --end --private]` | Fills nullable startDate/endDate automatically. Raw `post /projects/:id/milestones '{"name":"X"}'` returns `400 body/startDate Required` - always use the shortcut. |
|
|
35
|
+
| Update field | `patch-ticket ORB-42 <field> <value>` | Fields: title, description (inline text or `--stdin` - **never** `@/tmp/...`; `@path` only works for files that exist in the checked-in repo), type, priority, deliveryMode (ORB-1608 - implementation/docs/review/admin/epic), dueDate, startDate, status (category), milestone (name), isPrivate, estimatedTimeMinutes |
|
|
36
|
+
| Update project | `patch-project ORB <field> <value>` | Fields: name, description, key, status (draft/active/archived/closed), branchTemplate, customerId. Nullable fields (description / branchTemplate / customerId) accept the literal `null` to clear. Renaming the `key` rewrites every ticket's `PROJ-N` reference - handle with care. |
|
|
37
|
+
| Create project | `create-project <name> [--key XYZ] [--description "..." \| --description-stdin] [--customer <uuid>]` | Creates a new project. When `--key` is omitted the API auto-derives one from the name (uppercase initials). Returns `{ id, key, name, status, url }`. Caller needs `admin:project:create` or super-admin. Creating a project **auto-provisions a general doc space** (`<key>-general`, system-generated) - don't `create-doc-space` for the new project's docs, reuse that one. |
|
|
38
|
+
| Archive project | `archive-project <projectKey>` | Convenience for `patch-project <key> status archived` - moves a project out of active rotation without deleting data. Idempotent. Reversible via `patch-project <key> status active`. |
|
|
39
|
+
| List translations | `translation list [--status pending\|all] [--limit N] [--cursor C]` | Admin review queue for AI auto-translated tickets (ORB-893). Default `pending` filter; pass `all` to see reviewed rows too. Cursor-paginated. Requires `admin:translation_review`. |
|
|
40
|
+
| Approve translation | `translation approve <ticketUUID>` | Stamp the row reviewed. Idempotent. |
|
|
41
|
+
| Revert translation | `translation revert <ticketUUID>` | Restore the pre-translation title + description from the audit comment and clear the auto-translate marker. |
|
|
42
|
+
| List drift | `drift list [--user UUID] [--type untracked_commit\|transition_without_summary] [--from ISO] [--to ISO] [--resolved true\|false] [--limit N] [--cursor C]` | Agent drift log (ORB-543): commits with no ticket key + no timer, or transitions without a summary comment. Cursor-paginated + aggregate metrics. `enabled:false` in the response = detection is off. Requires `admin:agent_drift:read`. MCP: `orboto_admin_agent_drift_list`. |
|
|
43
|
+
| Show drift | `drift show <eventUUID>` | Full detail of one drift event (matched against the recent window). |
|
|
44
|
+
| Resolve drift | `drift resolve <eventUUID>` | Mark one drift event handled. Idempotent. Requires `admin:agent_drift:write`. MCP: `orboto_admin_agent_drift_resolve`. |
|
|
45
|
+
| Move status | `move ORB-42 <category>` | `todo` / `in_progress` / `in_review` / `done`. **Returns `summaryWarning` (ORB-1332)** when moving to `in_review`/`done` with no recent summary comment - non-blocking, printed on STDERR. |
|
|
46
|
+
| Close ticket | `close ORB-42 [--comment "..."]` | Move to done + optional comment (the comment doubles as the transition summary and suppresses the `summaryWarning`; closing without one returns a non-blocking `summaryWarning`, ORB-1332). If the active timer is on this ticket it's auto-stopped with a note; timers on other tickets are untouched. `--no-timer` skips. |
|
|
47
|
+
| Delete ticket | `delete-ticket ORB-42 --force` | **DESTRUCTIVE, IRREVERSIBLE** hard-delete (row + history gone, fires `ticket.deleted` webhook). `--force` required. **Prefer `move ORB-42 wont_fix`** for dupes/superseded/out-of-scope - keeps history. Hard-delete only what should never have existed. MCP equivalent: `orboto_delete_ticket`. |
|
|
48
|
+
| Claim ticket | `claim ORB-42` | Add self as assignee (additive) + in_progress + start timer. Idempotent. `--sole` to take over, `--force` to reopen done. |
|
|
49
|
+
| Unclaim ticket | `unclaim ORB-42` | Unassign self + move to todo (opposite of claim) |
|
|
50
|
+
| Assign user | `assign ORB-42 <email-or-userId>` | Resolves email automatically |
|
|
51
|
+
| Unassign user | `unassign ORB-42 <email-or-userId>` | |
|
|
52
|
+
| Set milestone | `set-milestone ORB-42 <MS-key | "Name" | UUID>` | Resolves key/name automatically |
|
|
53
|
+
| Set RACI role | `set-raci ORB-42 <email-or-userId> <R\|A\|C\|I>` | RACI responsibility role. **Opt-in per project** - only use when the project has RACI enabled (`raciEnabled` on the project); never raise/suggest RACI on a project that hasn't opted in. Needs `ticket:manage_raci`. A second Accountable (A) is rejected, naming the current one. MCP: `orboto_set_raci`. |
|
|
54
|
+
| RACI matrix | `raci <projectKey> [--milestone "..."] [--epics-only]` | Tickets x members, cells = R/A/C/I. **Opt-in** - empty + don't raise it until the project enables RACI. MCP: `orboto_raci`. |
|
|
55
|
+
| List approvals | `approvals ORB-42` | ORB-1223 - a ticket's approval / sign-off requests (change-management gates on status transitions): target status, mode, progress, and whether you can vote. A gated move returns 409 `approvalRequired` and opens a pending request; it stays blocked until sign-offs land, then the requester re-applies the move. MCP: `orboto_list_approvals`. |
|
|
56
|
+
| Decide approval | `approve ORB-42 [--comment "..."] [--request <id>]` / `reject ...` | ORB-1223 - cast an approve/reject vote on a pending sign-off request. You must be an eligible approver (policy role / named user / a RACI role on the ticket), else 403; you cannot approve your own request. A single reject resolves it; enough approvals unblock the transition. MCP: `orboto_approval_decide`. |
|
|
57
|
+
| Diff fingerprint | `git diff \| orboto review-fingerprint` | ORB-1615 - normalize + hash raw diff text into a canonical fingerprint (server-side, one algorithm - never hash it yourself), plus real size metrics (filesChanged/linesAdded/linesRemoved/paths). Whitespace-only/blank-line-only edits and file order are invisible to the hash (an approval survives a reflow); any real content change, a permission/mode change, or an added/removed/renamed file is NOT. Stateless - nothing is persisted. Feed the result into `review-check` and `review-approve`/`review-reject`. MCP: `orboto_review_fingerprint`. |
|
|
58
|
+
| Check review policy | `review-check ORB-42 [--fingerprint <fp>] [--paths <csv>] [--lines <n>]` | ORB-1615 - **consult BEFORE spawning a reviewer or invoking a model.** With no flags (right after picking up a ticket, no diff yet) resolves the per-ticket override or a deliveryMode-only rule; `--paths`/`--lines` (from `review-fingerprint`) refine the match against path/size-scoped rules; `--fingerprint` additionally checks for an existing VALID approval at this exact diff. `riskLevel: "none"` -> skip the reviewer. `riskLevel: "required"` with `source: "fail_safe"` means the policy engine itself errored - treat as required, never as no-review-needed. MCP: `orboto_review_policy_check`. |
|
|
59
|
+
| Record review decision | `review-approve ORB-42 --fingerprint <fp> [--note "..."] [--files <n>] [--added <n>] [--removed <n>] [--paths <csv>]` / `review-reject ...` | ORB-1615 - record your verdict against a diff fingerprint (from `review-fingerprint`). Requires `ticket:record_review_approval`. A recorded approval is reusable: `review-check` reports it valid for the SAME fingerprint - the moment the diff changes, the fingerprint changes and it stops matching, no separate revoke needed (revoke exists for "changed my mind, no new commit": `POST /projects/:id/tickets/:id/review-approvals/:approvalId/revoke`). MCP: `orboto_review_approval_record`. |
|
|
60
|
+
| Add dependency | `add-dependency ORB-B ORB-A` | "B depends on A" / "A blocks B". Use this - NEVER write "blocked by X" as a free-text comment; the dependency primitive is what powers the dependency panel, Gantt arrows, and the `blockedBy` OQL filter. **ORB-1614 - cross-project:** A and B may live in DIFFERENT projects (e.g. `add-dependency OVB-55 UAI-6`) as long as you can read both - the API 403s with a forbidden error otherwise. Self-dependencies and cycles (including cycles that span projects) are rejected. |
|
|
61
|
+
| List dependencies | `list-dependencies ORB-B` | Shows both sides: tickets B depends on, and tickets B blocks. **ORB-1614:** an edge to a ticket in another project you cannot read comes back as an opaque stub - `ticketKey`/`title`/`projectId`/status all `null`, `external: true`, `resolved: <bool>` (whether it's currently done/wont_fix - the one bit needed to answer "is this still blocking me", deliberately with nothing else identifying). |
|
|
62
|
+
| Remove dependency | `remove-dependency ORB-B ORB-A` | Inverse of add-dependency. Works even when you can no longer (or never could) read the far ticket - severing a link never requires seeing the other end. |
|
|
63
|
+
| Add cross-project link | `add-cross-link ORB-42 OCP-7 counterpart [--sync]` | ORB-945 - formal relation between two tickets in DIFFERENT projects. Relations: `counterpart` (parallel work in two repos) / `depends_on` (this waits for the other) / `blocks` (the other waits for this) / `related` (loose). `--sync` opts the link into auto-close when a counterpart-typed link's other end moves to done (sub-ticket ORB-947 ships the runtime). **Business-tier `.ee.*` feature** - works in every tier with a per-admin soft-warn banner. Caller must be a member of BOTH source + target projects. |
|
|
64
|
+
| List cross-project links | `list-cross-links ORB-42` | Both outgoing + incoming links with the other end's project key + ticket key + title + current status. ACL-filtered. |
|
|
65
|
+
| Remove cross-project link | `remove-cross-link ORB-42 <linkId>` | Drop the relation row. Tickets stay; only the link is deleted. |
|
|
66
|
+
| Search | `search <query> [--types=ticket,doc,comment] [--project=KEY] [--limit=10]` | Unified full-text search; visibility-filtered |
|
|
67
|
+
| API endpoint search | `api-search <terms> [--limit=8]` / `api-search --path </route/{id}> --method <M>` | ORB-1518 - Code-Mode escape hatch (discovery half): ranked endpoint search over the live OpenAPI spec (method, path, required permission slugs, parameter names; `?` suffix = optional), or one endpoint's full parameter/request/response schema via `--path`+`--method`. Execute what you found with the raw `get/post/patch/put/delete` commands. Backed by the authenticated `GET /system/api-catalog` routes - always current, never hand-maintained. MCP: `orboto_api_search`. |
|
|
68
|
+
| API call (escape hatch) | raw `get/post/patch/put/delete <path> [json]` | The wrapper's execute half - direct REST with your own permissions. MCP clients use `orboto_api_call` instead (ORB-1519): a structured proxy via `POST /system/api-proxy` that dispatches through the full auth + permission chain and returns the inner status + body as data (envelope). Proxy blocks auth/OAuth/setup/webhook paths + unknown routes, 120/min. Prefer named tools/shortcuts when one exists. |
|
|
69
|
+
| OQL query | `query "<oql>" [--syntax=oql\|jql] [--limit=25] [--cursor=...] [--explain]` | Typed query DSL - combines AND/OR/NOT, IN, IS [NOT] EMPTY, ORDER BY, LIMIT, functions like `currentUser()` / `daysAgo(n)`. See "OQL - orboto Query Language" below. |
|
|
70
|
+
| Project primer | `primer <projectKey> [--max-tokens N]` | Auto-generated session primer (active milestones / ticket counts / top docs / structured `primer_facts` / recent activity) in one call. Repo briefings (CLAUDE.md / AGENTS.md) only land in the primer when the operator configured them AND the API host can read those files from disk - most deployments will not have them. Token-budget aware - drops lowest-priority sections first. Always run this when starting work on an unfamiliar project. |
|
|
71
|
+
| List primer facts | `primer-fact list <projectKey> [--category X] [--source S] [--verified true\|false] [--include-workspace true\|false]` | Read structured facts that feed the primer. Workspace-wide facts (apply to every project) merge in by default; pass `--include-workspace false` to see only project-scoped rows. |
|
|
72
|
+
| Add primer fact | `primer-fact add <projectKey> --category <cat> --key <k> --value "<v>" [--observed]` | Record a structured fact (tech stack, convention, deployment quirk, …). `--observed` marks it as bot-recorded and pending operator verification. Long markdown bodies: `--value-stdin` + heredoc. |
|
|
73
|
+
| Update primer fact | `primer-fact update <factId> [--value "<v>" \| --value-stdin] [--category <cat>] [--key <k>]` | Partial patch. Bumps `lastVerifiedAt` automatically when value changes; pure renames leave it untouched. |
|
|
74
|
+
| Supersede primer fact | `primer-fact supersede <factId> --category <cat> --key <k> --value "<v>"` | Replace a wrong fact while preserving history (the old row gets `superseded_by_id`). New row starts unverified. |
|
|
75
|
+
| Verify primer fact | `primer-fact verify <factId>` | Operator-only: promotes an `agent_observed` fact to verified. Removes the `(observed)` marker from the rendered primer. |
|
|
76
|
+
| Delete primer fact | `primer-fact delete <factId> [--reason "<r>"]` | Hard-delete. Prefer `supersede` when the fact is being replaced; only delete when wrong from the start. |
|
|
77
|
+
| Session start / re-orient | `session-start [--project <key>] [--ticket <PROJ-N>]` | Run at the START of every session AND right after a context compaction. Prints a briefing: the workspace working-rules, your in-progress tickets, and your running timer - the points where agents lose the thread. MCP: `orboto_session_start` (`projectId` / `ticketKey` inputs). `orboto init` also wires a Claude Code SessionStart hook that runs it automatically. **Session-start gate (ORB-1471):** a workspace can set `mcp_require_session_start` so the MCP server REFUSES every other tool call until `orboto_session_start` has run once this session - if a tool returns "call orboto_session_start first", run it, then retry. **Lean rules ack (ORB-1607):** `GET /agent-instructions` returns a stable `rulesHash`; both the wrapper (cached in a `.rules-hash` dotfile beside `.env`) and the MCP tool (in-memory per connection) send their last-known hash back as `knownRulesHash` - an unchanged hash collapses the full rules block into `{ rulesHash, rulesUnchanged: true }` instead of re-sending the text. **`--ticket PROJ-N` one-shot bundle (ORB-1607):** additionally returns that ticket's project primer, full ticket detail (incl. dependencies + checklists), the project's git health, and any other agent sessions already on it - replacing several separate calls (primer, ticket, checklists, dependencies) at the point an agent has the least context loaded. **`--force-rules` (ORB-1697):** the hash ack above is keyed to this CHECKOUT (dotfile) / this MCP CONNECTION - neither of which ends when YOUR context does. After a compaction or a `/clear`, the ack will say the rules are unchanged while you no longer hold them. When that is your situation, pass `--force-rules` (MCP: `forceRules: true`) and read the full set; never work from a half-remembered rule set to save tokens. With `--ticket`, open work in OTHER projects collapses to a count (use `my-tickets` to list it). |
|
|
78
|
+
| Agent rules (manage) | `get /agent-instructions/blocks?scope=workspace` ; `post /agent-instructions/blocks?scope=personal '{"title":"…","body":"…"}'` ; `patch /agent-instructions/blocks/:id '{"enabled":false}'` ; `delete /agent-instructions/blocks/:id` | Manage configurable agent rules at a scope: `workspace` (admin:ai:write), `customer` (customer:write, pass `&customerId=` - applies to every project of that customer), `project` (project:edit, pass `&projectId=`), or `personal` (your own). Precedence workspace → customer → project → personal (more specific wins). Default blocks edit/toggle/reset but not delete; custom delete. MCP: `orboto_*_agent_instruction` (scope param). The assembled rules an agent follows come from `get /agent-instructions` (read-only, context-merged). |
|
|
79
|
+
| View ticket checklists | `checklist <key|UUID>` | Compact tree of every checklist on a ticket with 1-based item indexes. |
|
|
80
|
+
| Check / uncheck item | `check <key> <idx|UUID>` · `uncheck <key> <idx|UUID>` | Tick a checklist item. Index is 1-based within the list; UUID works too. |
|
|
81
|
+
| Add checklist item | `add-check <key> "<content>" [--list "name"] [--link ORB-ID]` | Append an item to a list (first list by default). `--link` makes the item track another ticket's status. |
|
|
82
|
+
| Remove checklist item | `remove-check <key> <idx\|UUID>` | DESTRUCTIVE - delete a checklist item. Same item-ref semantics as check/uncheck. MCP: `orboto_remove_check`. |
|
|
83
|
+
| New checklist | `new-checklist <key> "<title>" [--triggers-done]` | Create a fresh checklist. `--triggers-done` gates ticket auto-done on this list. |
|
|
84
|
+
| List milestones | `milestones <projectKey>` | UUID + key (`ORB-M3`) + name + start/end per row |
|
|
85
|
+
| Critical path (CPM) | `critical-path <projectKey> [--milestone "..."] [--include-closed-milestones]` | Critical dependency chain + per-ticket slack (total float, working days). Durations from estimates. Deadline-aware: ticket/milestone due dates seed the schedule, so float can go negative and a DEADLINE RISKS section lists tickets that cannot meet their deadline with the shortfall. Closed-milestone tickets hidden by default. **ORB-1614:** a dependency edge to a ticket in ANOTHER project is followed one hop (not that ticket's own further cross-project blockers) when you can read it, marked `external: true`; an edge to one you cannot read is silently absent from the graph, same as any other out-of-window ticket. Cycle (including one spanning projects) reported instead of a path. MCP: `orboto_critical_path`. |
|
|
86
|
+
| Analytics + EVM | `analytics <projectKey> <report> [--milestone "..."] [--mode hours\|money]` | report = overview/burndown/velocity/cycle-time/workload/budget/collaboration/earned-value/estimation-accuracy/flow-time/flow-metrics/forecast/bottleneck. collaboration = human-only/agent-only/mixed ticket classification from the agent-work stamps + agent share of effort per project/milestone/member + weekly trend (`--milestone` scopes). bottleneck = longest-dwell status + predictability variance + aging. forecast = Monte-Carlo "done by X" (p50/p85/p95, --milestone scopes). flow-metrics = WIP (leaf tickets only; `epicWip`/`epicWipByCategory` report epics separately)/throughput/flow-efficiency/aging-WIP/CFD. flow-time = lead vs cycle vs effort, median + p75/p90 split by cohort/size/type; sub-day medians round to 0 in the day fields, check `leadMinutes`/`cycleMinutes` for fast cohorts. estimation-accuracy = estimate-vs-actual calibration (multiplier + confidence). ORB-1606: on bottleneck/flow-time/flow-metrics/estimation-accuracy, prefer `byWorkOrigin`/`cohortsByWorkOrigin`/`predictabilityByWorkOrigin` (agent/human/mixed, from WHO did the work) over the legacy `byCohort`/`cohorts`/`predictability` (agents/humans/combined, account type only - misses an agent operating through a human account). Gated: `analytics:view` for charts; `budget:view` for budget + EVM money mode (403 otherwise). MCP: `orboto_analytics`. |
|
|
87
|
+
| Portfolio rollup | `get /admin/portfolios` (list) / `get /admin/portfolios/<id>/rollup` (aggregate) | Portfolio / program-level cross-project reporting. List returns each portfolio (id/name/projectCount); the rollup aggregates per-project RAG (red/amber/green) health, progress (done/total), effort hours, aggregate Earned Value (SPI/CPI across projects with a baseline), a per-currency budget rollup, and the at-risk milestones (overdue or soon-due) across the whole portfolio. **ACL-filtered server-side**: only the projects you are a member of (super-admin sees all) and the tickets/milestones/budgets you may see contribute - `hiddenProjectCount` states how many were omitted, so it never leaks a project you cannot access. Money figures only appear for projects where you hold `budget:view`. Needs `admin:portfolio:read`; managing portfolios (create/edit/delete via `POST/PATCH/DELETE /admin/portfolios`) needs `admin:portfolio:write`. Add `Accept: text/csv` to the rollup for the per-project RAG grid as CSV. MCP: `orboto_portfolio_summary`. |
|
|
88
|
+
| Customer report | `customer-report <projectKey> [--preset scope\|status] [--locale ..] [--price-mode hours\|money\|lumpSum] [--lump-sum N] [--lump-sum-currency EUR]` | Generate the customer-facing project report as Markdown. `preset`: scope (proposal - milestones + epics, no progress) or status (all non-private tickets + progress). `format`: markdown or pdf (the wrapper prints markdown only; pdf/docx are binary downloads via the app/API). `locale`: en/de/fr/it/es/sv (structure labels catalog-translated). `options.priceMode`: hours (estimates) / money (customer rates, needs `budget:view`) / lumpSum (flat price). Private tickets/milestones always excluded; internal cost never included. Saved configs live at `.../customer-report-configs` (CRUD). Needs `customer_report:generate`. MCP: `orboto_customer_report` (markdown). |
|
|
89
|
+
| Requirements spec (Pflichtenheft) | `requirements-spec <projectKey> [--outline-variant neutral\|industry\|software] [--locale ..] [--price-mode hours\|money\|lumpSum] [--lump-sum N] [--lump-sum-currency EUR]` (alias `pflichtenheft`) | Generate the requirements specification (Pflichtenheft) as Markdown: numbered functional requirements (FA-1, FA-1.1...) each traceable to its ticket and tagged muss/soll/kann from priority, plus non-functional requirements distilled from primer facts. `outlineVariant`: neutral (default) / industry (VDI-3694 naming + order) / software (IEEE-830 naming + order). `format`: markdown or pdf/docx (the wrapper prints markdown only; pdf/docx are binary downloads via the app/API). `locale`: en/de/fr/it/es/sv. `options.priceMode`: hours (estimates) / money (customer rates, needs `budget:view`) / lumpSum (flat price). Private tickets/milestones always excluded; internal cost never included. Saved configs live at `.../requirements-spec-configs` (CRUD). Needs `requirements_spec:generate`. MCP: `orboto_requirements_spec` (markdown). |
|
|
90
|
+
| List statuses | `statuses <projectKey>` | Category + name + color + sort order |
|
|
91
|
+
| List labels | `labels <projectKey>` | UUID + name + color |
|
|
92
|
+
| Create label | `create-label <projectKey> <name> [--color "#rrggbb"]` | Create a label so `create-ticket --label NAME` can reference it (the API errors on unknown label names - it does NOT auto-create). Idempotent: returns the existing label if the name already exists. Needs `project:edit`. MCP: `orboto_create_label`. |
|
|
93
|
+
| Label a ticket | `label ORB-42 <labelName>` | Attach an existing label (by name) to an existing ticket. Create the label first if needed. Needs `ticket:edit`. MCP: `orboto_label_ticket`. |
|
|
94
|
+
| Unlabel a ticket | `unlabel ORB-42 <labelName>` | Remove a label from a ticket. MCP: `orboto_unlabel_ticket`. |
|
|
95
|
+
| Post comment | `comment ORB-42 "text" [--attach <path>[:alt] …]` | `--attach` repeats; image gets uploaded to the ticket and embedded in the comment as `` |
|
|
96
|
+
| Attach file(s) | `attach <key> <path…> [--alt "text"] [--embed]` | Uploads each file to the ticket. Prints markdown image lines. With `--embed`, appends them to the ticket description in a follow-up PATCH. |
|
|
97
|
+
| List attachments | `attachments <key>` | List a ticket's attachments (id, filename, contentType, sizeBytes, url), newest-first. `orboto_get_ticket` also surfaces the same array. Feed an `id` to `download-attachment`. MCP: `orboto_list_ticket_attachments`. |
|
|
98
|
+
| Download attachment | `download-attachment <id> [outPath]` | Fetch an attachment's bytes via the authenticated base64 route (auth + ACL, unlike the public `/attachments/:id` capability URL) and write them to `outPath` (default `./<filename>`); prints the saved path so an FS-capable agent can then read the image/file. Works for ticket/doc/comment attachments (id is global). MCP equivalent that returns an image content block to the model: `orboto_get_attachment`. |
|
|
99
|
+
| Internal comment | `post /tickets/:id/comments '{"content":"…","isInternal":true}'` | Hidden from guests |
|
|
100
|
+
| List comments | `get /tickets/:id/comments` | |
|
|
101
|
+
| Log time | `post /tickets/:id/time-entries '{"date":"YYYY-MM-DD","durationMinutes":60,"description":"…"}'` | |
|
|
102
|
+
| Start timer | `timer-start ORB-42` | |
|
|
103
|
+
| Stop timer | `timer-stop "note"` | |
|
|
104
|
+
| Start work session | `work-start ORB-42 [--role review] [--lease 900] [--takeover] [--no-timer] [--claim-path <glob> ...] [--claim-named <name> ...] [--claim-read <glob\|named:name> ...] [--on-conflict reject\|queue]` | ORB-1609 - take the (ticket, role) work lease and start its timer. Exactly ONE active session per (ticket, role) exists workspace-wide, ACROSS accounts: a colliding agent gets a 409 naming the holder instead of a silent collision discovered at push time. Re-running with the same instance renews your own lease (safe to call defensively). `--role review|preflight|integration` attaches to the ticket WITHOUT reassigning it or moving its status - use it for review passes and other work that produces no commit of its own. The lease expires by itself (default 15 min, auto-renewed by your subsequent calls), so a crashed agent never wedges a ticket. Returns `sessionId` - keep it for `work-finish`. ORB-1610 - `--claim-path`/`--claim-named` request WRITE claims (repeatable), `--claim-read` a read claim (never conflicts with anything); a write claim conflicts with any OVERLAPPING active write claim workspace-wide - path globs via segment-wise `*`/`**`/`?` matching, named resources via exact string equality. `--on-conflict reject` (default) 409s naming every conflicting holder and rolls back a brand-new session rather than leaving it claim-less; `queue` accepts the conflicting claim as waiting instead, auto-promoted once the conflict clears. ORB-1611 - calls the bundled `POST /work-sessions/start`, so the SAME call also returns (and prints) the rules-hash ack, the project primer, the ticket enriched with description/status/checklists/dependencies, that project's git health, and any sibling sessions on the ticket - replacing the separate `session-start --ticket` + primer + checklist + dependency calls a ticket pickup used to cost. The rules-hash ack is cached in the same dotfile `session-start` uses, so a repeat `work-start` with an unchanged ruleset gets the compact ack. |
|
|
105
|
+
| Dispatch pull (next ready ticket) | `work-next <PROJECT> [--role implementation\|review\|preflight\|integration] [--lease 900] [--no-timer] [--claim-path <glob> ...] [--claim-named <name> ...] [--claim-read <glob\|named:name> ...] [--on-conflict reject\|queue]` | ORB-1613 (Wave 3 of ORB-1602) - the pull side of low-management dispatch for worker pools: picks the highest-priority TODO ticket in a project that is unblocked (every dependency closed), not already leased under the requested role, and not blocked by a conflicting resource claim, then reserves it through the EXACT same atomic path `work-start` uses and returns the same context bundle (rules ack, primer, ticket, checklists, dependencies, git health, siblings). Priority then ticket number - deterministic, never a coin flip on ties. Epics are never returned (a container isn't directly implementable). Two workers calling this concurrently never receive the SAME ticket - a collision on the winning candidate just advances to the next one; the partial-unique-index INSERT is what actually guarantees it. When nothing is ready, prints a structured "nothing ready" line with a reason (`none-matching` / `all-blocked` / `all-leased`) and, only when derivable from an actual active lease, a retry-after hint - and exits **3** (not 0, not a hard error) so a polling loop can distinguish "back off" from "something broke". `--claim-*`/`--on-conflict` have the same semantics as `work-start`'s. |
|
|
106
|
+
| Finish work session | `work-finish <sessionId> [--commit <sha>] [--cancel] [--build] [--tests] [--lint] [--notes "..."] [--status <category>] [--note "..."]` | ORB-1609 - book the time, free the lease, record the evidence (commit + which gates you actually ran), and (ORB-1610) release every resource claim the session held, running a grant pass so the earliest queued waiter is promoted. Idempotent: finishing twice succeeds and still absorbs late evidence. Without `--status`, does NOT close the ticket - `close` stays a separate, deliberate decision. ORB-1612 - pass `--status <todo\|in_progress\|in_review\|done\|wont_fix>` to opt into the bundled one-call exit (`POST /work-sessions/:id/finish-work`): the same finish PLUS the ORB-1608 deliveryMode-aware ticket transition and a completion note (`--note` to override the auto-generated one). Only an `implementation`-role session with outcome `finished` drives the ticket - `review`/`preflight`/`integration` sessions attach without reassigning it (ORB-1609), and `--cancel` never auto-closes. `--commit` is recorded as an ATTESTATION immediately and verified asynchronously once git ingestion catches up - never blocks this call, which is exactly the fix for a close stuck for hours behind a lagging git connection. Idempotent the same way: re-running once the ticket is already at the target category is a no-op, not an error. A blocked transition (approval gate, dependency blocker, missing permission) is non-fatal - the session still finishes and the response says so. |
|
|
107
|
+
| List work sessions | `work-sessions [--ticket ORB-42] [--mine] [--include-closed]` | ORB-1609 - who OWNS what (as opposed to `agent-presence`, which is who is online). Check this before picking up work in a fleet: a ticket with a live `implementation` lease is already being worked. |
|
|
108
|
+
| Add resource claims | `work-claims add <sessionId> [--claim-path <glob> ...] [--claim-named <name> ...] [--claim-read <glob\|named:name> ...] [--on-conflict reject\|queue]` | ORB-1610 - declare more claims on a session you already hold, without touching the lease/timer. Same conflict rule and flags as `work-start`'s claim flags. |
|
|
109
|
+
| Release resource claims | `work-claims release <sessionId> [--claim-path <glob> ...] [--claim-named <name> ...] [--all]` | ORB-1610 - drop specific claims (matched by kind+value) or, with `--all`, every claim the session holds - WITHOUT finishing the session. Runs a grant pass immediately, so a queued waiter on the released resource is promoted as part of this call. |
|
|
110
|
+
| Timer state | `timer` | |
|
|
111
|
+
| List ticket schedules | `get /tickets/:id/schedules[?includeCancelled=true]` | ORB-626 - working sessions scheduled on a ticket (active by default). MCP: `orboto_list_ticket_schedules`. |
|
|
112
|
+
| Schedule a session | `post /tickets/:id/schedules '{"startsAt":"ISO","endsAt":"ISO","attendeeUserIds":["uuid"],"externalEmails":["a@x.io"],"title":"…","location":"…","notes":"…"}'` | ORB-626 - drops a plan-block on every orboto attendee + emails an iCal (RFC 5545) invite to all attendees. Needs `ticket:edit`. MCP: `orboto_schedule_ticket_session`. |
|
|
113
|
+
| Cancel a session | `delete /tickets/:id/schedules/:scheduleId` | ORB-626 - removes the plan-blocks + emails an iCal cancellation. Needs `ticket:edit`. MCP: `orboto_cancel_ticket_session`. |
|
|
114
|
+
| Create branch | `post /tickets/:id/git-branch` | Needs a configured Git connection on the project |
|
|
115
|
+
| Git activity | `get /tickets/:id/git-activity` | Check `latestPrState` before closing |
|
|
116
|
+
| GitHub App installs | `get /admin/git-app-installations` | Super-admin only. Returns every App install orboto knows about; rows carry account-login + suspended state. |
|
|
117
|
+
| Search | `get /search?q=<terms>` | Tickets, docs, comments - visibility-filtered |
|
|
118
|
+
| Absences | `get /absences` / `post /absences` | For OOO planning |
|
|
119
|
+
| Edit absence | `patch /absences/:id '{"startDate":"YYYY-MM-DD","note":"…"}'` | ORB-933 - owner-only; locked once approved/rejected/cancelled. `durationDays` is recomputed on date change. Fields: typeId, startDate, endDate, note. |
|
|
120
|
+
| Blocked days | `get /calendar/blocked-days?from=&to=` | Holidays + closures + approved absences |
|
|
121
|
+
| Edit public holiday | `patch /admin/public-holidays/:id '{"date":"YYYY-MM-DD"}'` | ORB-933 - typo / wrong-date correction without losing the row id. Admin (`admin:absences:write`). Fields: name, date, countryCode, regionCode, isRecurring. |
|
|
122
|
+
| Edit company closure | `patch /admin/company-closures/:id '{"endDate":"YYYY-MM-DD"}'` | ORB-933 - partial-patch validates start ≤ end against the unchanged counterpart. Admin (`admin:absences:write`). Fields: name, startDate, endDate, note. |
|
|
123
|
+
| Project members | `get /projects/:id/members` | Returns `{ userId, projectId, roleId, user: { id, email, fullName, avatarUrl }, role: { id, name } }` per member |
|
|
124
|
+
| Agent heartbeat | `agent-heartbeat [--status idle\|working\|blocked] [--working-on <ticketUUID>] [--client <name>] [--capabilities a,b,c] [--token …]` | ORB-704/705 - register / refresh this agent's presence in the workspace. Returns `{ sessionToken, sessionId }` - persist token for re-bumps. See the "Multi-Agent Coordination" section above for the routine. |
|
|
125
|
+
| Agent presence | `agent-presence` | ORB-704/705 - list active agent sessions visible to caller. Super-admin: everyone. Regular user: own sessions only. |
|
|
126
|
+
| Agent notify | `agent-notify <target-email> "<subject>" [--kind info\|request\|complete\|error] [--thread <messageId>] [--payload <json>] [--project <key\|uuid>]` | ORB-705/ORB-1727 - directed message to another agent / user, now DURABLE: lands in the recipient's inbox even when they are offline (their next orboto call carries a pending-mail pointer), plus the live notification push for connected MCP subscribers. `--thread` replies to an inbox message. ORB-1732: `--project` scopes it to "the agent working project X" when the recipient identity runs multiple sessions. |
|
|
127
|
+
| Agent inbox | `messages [--all] [--limit N] [--project <key\|uuid>] \| messages --ack <id,id,...>` | ORB-1727 - fetch the messages other agents sent you (store-and-forward; fetch marks delivered, `--ack` marks read and stops the pending pointer). ORB-1732: `--project` narrows to messages scoped to that project PLUS unscoped ones (unscoped mail is never hidden); only ack what you actually handled. MCP: `orboto_messages`. |
|
|
128
|
+
|
|
129
|
+
| Truncated MCP response | MCP only: `orboto_response_expand { handle, path?, cursor? }` | ORB-1697 - the MCP server caps what one tool result may inject into a session (default 4k characters, higher for content reads like `get_doc` / `session_start`), because a result is re-sent on EVERY later request of that session. An over-budget result carries `__truncation { handle, budgetChars, omittedChars, omitted[] }` and each cut value ends in a `[truncated N chars ...]` marker - never a silent cut. Call this tool with the `handle` alone to list what was omitted, then with a `path` from `omitted[].path` (`$text` for the human-readable block) and follow `nextCursor` to read the rest. Handles live 15 minutes in the MCP server process; if one expired, re-run the original tool. This is MCP transport plumbing - the REST API and this wrapper are never truncated, so `scripts/orboto.mjs` has no equivalent. |
|
|
130
|
+
|
|
131
|
+
Exact path params and body shapes live in the OpenAPI spec (`get /docs/json`). On a 400 "body must match", re-read the spec for that route - don't retry blindly.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## AI-dependent operations
|
|
136
|
+
|
|
137
|
+
Some skill shortcuts only work when the workspace operator has configured an AI provider in Admin → AI Settings. Run `orboto ai-status` first when in doubt - it returns `{ configured, embeddingsConfigured }`.
|
|
138
|
+
|
|
139
|
+
| Shortcut | Needs `configured` | Needs `embeddingsConfigured` | Behaviour when off |
|
|
140
|
+
|---|---|---|---|
|
|
141
|
+
| `ask-docs` | yes | yes (RAG step) | 400 "AI is not configured" - degrade to `search` for keyword-only Q&A |
|
|
142
|
+
| `ingest-url` / `ingest-file` | no | no | Doc gets created either way; only RAG search via `ask-docs` is unavailable until embeddings are configured |
|
|
143
|
+
| `primer` | no | no | Always works - the renderer never calls AI |
|
|
144
|
+
| `primer-fact *` | no | no | Always work |
|
|
145
|
+
| Everything else (`whoami`, `ticket`, `query`, `claim`, `patch-ticket`, `bulk-*`, …) | no | no | Always work |
|
|
146
|
+
|
|
147
|
+
Anthropic-only deployments report `{ configured: true, embeddingsConfigured: false }` because Anthropic does not produce embeddings. Chat-only AI features still work; RAG features (`ask-docs` and similar) do not.
|
|
148
|
+
|
|
149
|
+
If `ai-status` reports `configured=false`, do not suggest AI-gated workarounds to the operator - the workspace owner has either not set it up or has deliberately turned it off.
|