@aiaiai-pt/martha-cli 0.4.0 → 0.5.1
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/CHANGELOG.md +28 -1
- package/README.md +36 -9
- package/dist/index.js +487 -96
- package/package.json +1 -1
- package/skills/martha-cli/SKILL.md +133 -38
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ Martha has a few distinct primitives that get confused in everyday talk. This is
|
|
|
15
15
|
|---|---|---|
|
|
16
16
|
| **Tenant** | Opaque data isolation boundary (`tenant_id` string). All queries filter by this. Set from the JWT, never from request body. | Every entity is tenant-scoped. You don't pass it explicitly to the CLI — it comes from your token. |
|
|
17
17
|
| **Client** | A chat-API consumer (web app, SMS sender, voice line). Has `keycloak_client_id`, `system_prompts`, allowlists. **Not a tenant.** | Use when you're configuring how a frontend or messaging channel talks to Martha. |
|
|
18
|
-
| **Agent** | An `AgentDefinition` row:
|
|
18
|
+
| **Agent** | An `AgentDefinition` row: `system_prompt` + LLM config + loop config + tool grants. Cloud or external. | Cloud agents are run by Martha (Temporal). External agents are remote harnesses that authenticate and execute Martha tasks. |
|
|
19
19
|
| **Team** | A named group of agents with a routing strategy (`round_robin`, `manual`, `external`). | Use to spread work across many similar agents (e.g. 5 ork instances doing code review). |
|
|
20
20
|
| **Task** | A unit of work with goal, priority, lifecycle (`open`/`claimed`/`running`/`completed`/`failed`/`cancelled`/`stale`/`poisoned`). Optionally linked to a tracker issue. | Use to queue async work for agents. Humans or agents can create them. |
|
|
21
21
|
| **Function** | An HTTP endpoint or platform Python callable that an agent can invoke as a tool. Stored as `FunctionDefinition`. | Define once, grant to many agents. |
|
|
@@ -35,7 +35,7 @@ Everything below operates on these primitives. When in doubt, run `martha status
|
|
|
35
35
|
| Flag | Purpose |
|
|
36
36
|
|---|---|
|
|
37
37
|
| `--json` | Machine-readable JSON output. **Always set this when piping to `jq` or parsing.** Without it, output is human-formatted and may include color codes. |
|
|
38
|
-
| `--profile <name>` | Use a named profile from `~/.martha/
|
|
38
|
+
| `--profile <name>` | Use a named profile from `~/.martha/config.yaml`. |
|
|
39
39
|
| `--api-url <url>` | Override `MARTHA_API_URL`. Useful for hitting staging/prod from the same shell. |
|
|
40
40
|
| `--verbose` | DEBUG-level logging on stderr. Shows HTTP requests, retry attempts, token expiry decisions. |
|
|
41
41
|
| `--quiet` | Suppress informational output. Errors still print. |
|
|
@@ -47,11 +47,28 @@ Everything below operates on these primitives. When in doubt, run `martha status
|
|
|
47
47
|
|
|
48
48
|
## Authentication
|
|
49
49
|
|
|
50
|
+
Install does not pre-provision a global profile. Configure one explicitly before
|
|
51
|
+
running commands:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Local development stack
|
|
55
|
+
martha init --no-interactive --preset local
|
|
56
|
+
|
|
57
|
+
# Customer, staging, or private-cloud tenant
|
|
58
|
+
martha init --no-interactive --name acme \
|
|
59
|
+
--api-url https://martha.acme.example \
|
|
60
|
+
--keycloak-url https://auth.acme.example \
|
|
61
|
+
--keycloak-realm acme
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use `martha init --preset cloud` only when you intentionally want the hosted
|
|
65
|
+
Martha cloud profile (`martha.nomadriver.co` + `keycloak.frank.nomadriver.co`).
|
|
66
|
+
|
|
50
67
|
The CLI resolves credentials in this priority order. The first non-empty wins:
|
|
51
68
|
|
|
52
69
|
1. `MARTHA_TOKEN` — raw JWT, bypasses all login flows. Highest priority.
|
|
53
70
|
2. `MARTHA_CLIENT_ID` + `MARTHA_CLIENT_SECRET` — OAuth2 client credentials, auto-refreshes.
|
|
54
|
-
3. Profile-stored token from prior `martha auth login` (cached
|
|
71
|
+
3. Profile-stored token from prior `martha auth login` (cached under `~/.martha/` for the active profile).
|
|
55
72
|
4. Browser-based OIDC (interactive only, won't fire in non-TTY).
|
|
56
73
|
|
|
57
74
|
```bash
|
|
@@ -130,9 +147,22 @@ agent_type: cloud
|
|
|
130
147
|
auth_method: service_account # Slice 3B: provisions Keycloak SA on create
|
|
131
148
|
system_prompt: "You write friendly morning briefings."
|
|
132
149
|
llm_config: { provider: anthropic, model: claude-sonnet-4-5-20250929 }
|
|
133
|
-
loop_config: {
|
|
150
|
+
loop_config: { max_iterations: 5 }
|
|
134
151
|
```
|
|
135
152
|
|
|
153
|
+
Agent field notes:
|
|
154
|
+
|
|
155
|
+
- `system_prompt` is the durable instruction for the agent.
|
|
156
|
+
- Grant an agent to a chat client with
|
|
157
|
+
`martha clients grant <client> agent <agent>` to make it callable as a tool
|
|
158
|
+
from that client.
|
|
159
|
+
- `runs_as_chat` is an advanced top-level chat-takeover override, not normal
|
|
160
|
+
provisioning. Use it only when exactly one chat client should replace its own
|
|
161
|
+
`system_prompt`, `llm_config`, and tools with one agent.
|
|
162
|
+
- `loop_config.enabled` is legacy compatibility. New YAML should not use it.
|
|
163
|
+
- Workflow `llm` nodes use `config.prompt` for a one-step task prompt; that is
|
|
164
|
+
separate from an agent `system_prompt`.
|
|
165
|
+
|
|
136
166
|
`--dry-run` prints what would change without writing. `--yes` skips the confirmation when applying to a non-empty tenant.
|
|
137
167
|
|
|
138
168
|
### Export (back up or migrate)
|
|
@@ -241,11 +271,11 @@ Default `execute_on` mapping: `llm` → `local`; `function` / `wait` / `transfor
|
|
|
241
271
|
```bash
|
|
242
272
|
martha agents list [--inactive] [--limit 50]
|
|
243
273
|
martha agents get <name> # Includes auth_method, status, llm_config, granted functions/workflows
|
|
244
|
-
martha agents create --name <n> --model <m> --prompt "system prompt" \
|
|
274
|
+
martha agents create --name <n> --model <m> --system-prompt "system prompt" \
|
|
245
275
|
[--description "..."] [--temperature 0.7] [--max-tokens 4096] \
|
|
246
276
|
[--type cloud|external] [--auth service-account|api-key] \
|
|
247
277
|
[--tags code-review,python] [--local-tools filesystem,git]
|
|
248
|
-
martha agents update <name>
|
|
278
|
+
martha agents update <name> -f agent.yaml
|
|
249
279
|
martha agents delete <name> [--hard] [--yes]
|
|
250
280
|
martha agents versions <name>
|
|
251
281
|
martha agents rollback <name> <version>
|
|
@@ -272,11 +302,13 @@ martha agents generate-key <agent>
|
|
|
272
302
|
**Function grants:**
|
|
273
303
|
|
|
274
304
|
```bash
|
|
275
|
-
martha agents add-function <agent> <function> [--set key=value]
|
|
276
|
-
martha agents remove-function <agent> <function>
|
|
305
|
+
martha agents add-function <agent> <function> [--set key=value] [--collection <slug-or-id>]
|
|
306
|
+
martha agents remove-function <agent> <function> [--collection <slug-or-id>]
|
|
277
307
|
martha agents functions <agent> # List granted functions
|
|
278
308
|
```
|
|
279
309
|
|
|
310
|
+
`--collection` scopes the grant to one collection per the #372 PR2 cascade. Omit it to grant at the root (tenant-wide); pass it on `remove-function` to revoke just that scope. Server returns 400 if the function is collection-agnostic (e.g. `recall`).
|
|
311
|
+
|
|
280
312
|
---
|
|
281
313
|
|
|
282
314
|
## Tasks: queue + executor lifecycle
|
|
@@ -482,38 +514,51 @@ martha tasks poll --json
|
|
|
482
514
|
|
|
483
515
|
A **Connection** is a stored credential record for an integration. Auth values live in HashiCorp Vault keyed by `(scope, scope_id, service_name)`. The DB only has metadata. Tracker connections include adapter-specific config (team_id, repository, project_id) stored as a flat dict in Vault — `resolve_connection_config()` is the single merge point for tracker adapter calls.
|
|
484
516
|
|
|
485
|
-
The CLI doesn't yet have a top-level `connections` subcommand — manage them via the admin UI at `/settings` (Trackers tab) or via the API:
|
|
486
|
-
|
|
487
517
|
```bash
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
518
|
+
martha connections list [--integration <name>] [--scope tenant|client|system]
|
|
519
|
+
martha connections create --integration <name> --name <name> --auth-type <type> \
|
|
520
|
+
--credential-value <value|@file|-> [--config '<json>'] \
|
|
521
|
+
[--scope tenant|client|system] [--scope-ref <ref>] [--not-default]
|
|
522
|
+
martha connections update <connection-id> [--credential-value <value|@file|->] \
|
|
523
|
+
[--config '<json>'] [--name <name>] [--default|--not-default]
|
|
524
|
+
martha connections test <connection-id>
|
|
525
|
+
martha connections delete <connection-id> --yes
|
|
526
|
+
```
|
|
491
527
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
528
|
+
**Rotating a service-account key:** `martha connections update <id> --credential-value @new-sa.json`
|
|
529
|
+
replaces the SA key in Vault in place (same connection id, sources stay attached)
|
|
530
|
+
and drops the cached SA token so the new key takes effect immediately.
|
|
495
531
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
"
|
|
532
|
+
`--credential-value` accepts a literal, `@path` (read a file), or `-` (read stdin).
|
|
533
|
+
`--config` is a non-secret JSON object stored in Postgres (never Vault).
|
|
534
|
+
**OAuth2 connections cannot be created from the CLI** — they need an interactive
|
|
535
|
+
browser consent flow; use the admin UI under Integrations → Connections.
|
|
536
|
+
|
|
537
|
+
```bash
|
|
538
|
+
# Google Drive via service account (#407) — reads enterprise Shared Drives
|
|
539
|
+
# without CASA. credential_value is the SA JSON key; config carries the
|
|
540
|
+
# optional impersonation subject (domain-wide delegation) + scopes.
|
|
541
|
+
martha connections create \
|
|
542
|
+
--integration google_drive --name "SOMENGIL Drive" \
|
|
543
|
+
--auth-type service_account \
|
|
544
|
+
--credential-value @/path/to/sa-key.json \
|
|
545
|
+
--config '{"subject":"owner@corp.com","scopes":["https://www.googleapis.com/auth/drive.readonly"]}'
|
|
546
|
+
# Then add the SA's client_email as a member (Viewer) of the Shared Drive.
|
|
507
547
|
|
|
508
|
-
#
|
|
509
|
-
|
|
510
|
-
|
|
548
|
+
# Linear connection (full config dict in JSON, stored as one Vault entry)
|
|
549
|
+
martha connections create --integration linear --name production \
|
|
550
|
+
--auth-type api_key \
|
|
551
|
+
--credential-value '{"api_key":"lin_api_xxx","team_id":"uuid-here"}'
|
|
511
552
|
|
|
512
|
-
#
|
|
513
|
-
|
|
514
|
-
"$MARTHA_API_URL/api/admin/connections/<connection-id>"
|
|
553
|
+
# Test a connection (calls the adapter's health check with merged config)
|
|
554
|
+
martha connections test <connection-id>
|
|
515
555
|
```
|
|
516
556
|
|
|
557
|
+
`martha connections create` mirrors `POST /api/admin/connections`. For
|
|
558
|
+
service_account it validates the key shape (`type`, `client_email`) before
|
|
559
|
+
submit. List available tracker adapters + their `config_schema` via
|
|
560
|
+
`curl -s -H "Authorization: Bearer $(martha auth token)" "$MARTHA_API_URL/api/admin/trackers" | jq`.
|
|
561
|
+
|
|
517
562
|
**Tracker connection auto-provisioning:** When you create a connection where `integration_name` matches a tracker (`linear`/`github`/`gitlab`), the backend automatically provisions:
|
|
518
563
|
1. A `webhook_definition` (returns one-time `webhook_url` + `webhook_secret` in the create response)
|
|
519
564
|
2. Three trigger definitions (managed by `tracker:{type}`):
|
|
@@ -579,9 +624,10 @@ Document collections are tenant-scoped containers that ingest files (PDF, DOCX,
|
|
|
579
624
|
|
|
580
625
|
```bash
|
|
581
626
|
# Collections
|
|
582
|
-
martha documents collections [--inactive] [--limit 50]
|
|
627
|
+
martha documents collections [--inactive] [--limit 50] [--tree] # --tree renders the parent/child hierarchy as ASCII (#372)
|
|
583
628
|
martha documents collection <id> # Stats, ingestion status, total size
|
|
584
|
-
martha documents create-collection --name "My Docs" [--description "..."]
|
|
629
|
+
martha documents create-collection --name "My Docs" [--description "..."] [--parent <slug-or-id>]
|
|
630
|
+
martha documents move-collection <id> --parent <slug-or-id> | --root # Atomic move; server rejects cycles
|
|
585
631
|
|
|
586
632
|
# Document lifecycle
|
|
587
633
|
martha documents upload <collection-id> <file> [--wait] [--follow] # --follow streams ingestion progress
|
|
@@ -608,6 +654,24 @@ A failed enrich step does NOT fail the document — it falls back to keyword-onl
|
|
|
608
654
|
|
|
609
655
|
---
|
|
610
656
|
|
|
657
|
+
## Document Sync (durable Drive/folder sync)
|
|
658
|
+
|
|
659
|
+
Durable sync sources mirror an external provider (Google Drive today) into Martha collections. Folder structure changes in Drive — move, rename, delete — propagate to the collection tree inbound (#372 PR5).
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
# Backfill / repair the collection tree from a Drive source's folder hierarchy.
|
|
663
|
+
# Stamps drive_folder_id on existing collections matching (parent, name) and
|
|
664
|
+
# creates sub-collections for unmapped Drive folders. Idempotent.
|
|
665
|
+
martha document-sync reconcile-tree --source <source-id> [--dry-run]
|
|
666
|
+
martha document-sync reconcile-tree --all [--dry-run] # every google_drive source
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
`reconcile-tree` is the one-shot backfill that maps a source connected before folder-sync existed (or repairs drift). It runs server-side against the source's live OAuth token, so the source must be connected and validatable. `--dry-run` prints the would-link / would-create / skipped counts without writing. Re-running is safe — already-linked folders are skipped.
|
|
670
|
+
|
|
671
|
+
Cross-source moves are rejected: a collection can't move between sync sources. Reorganize the folder in Drive directly and inbound sync mirrors it.
|
|
672
|
+
|
|
673
|
+
---
|
|
674
|
+
|
|
611
675
|
## Approvals (human-in-the-loop)
|
|
612
676
|
|
|
613
677
|
Approvals are pause-points inside workflows. The `approval_gate` workflow node creates an `ApprovalCase`; downstream nodes wait until a human resolves it.
|
|
@@ -653,11 +717,13 @@ martha clients update <name-or-id> [--name <n>] [--system-prompts '...']
|
|
|
653
717
|
martha clients delete <name-or-id> [--force] [--yes] # --force drops sessions
|
|
654
718
|
|
|
655
719
|
# Access grants — what definitions this client's sessions can use
|
|
656
|
-
martha clients grant <client> function|workflow|agent <def-name> [--config key=value]
|
|
657
|
-
martha clients revoke <client> function|workflow|agent <def-name>
|
|
720
|
+
martha clients grant <client> function|workflow|agent <def-name> [--config key=value] [--collection <slug-or-id>]
|
|
721
|
+
martha clients revoke <client> function|workflow|agent <def-name> [--collection <slug-or-id>]
|
|
658
722
|
martha clients access <name-or-id> # All grants for this client
|
|
659
723
|
```
|
|
660
724
|
|
|
725
|
+
`--collection` is only valid on `function` grants (#372 PR2). The same UUID, slug, or name accepted by `documents move-collection` works here. Granting a scope on a collection-agnostic function (like `recall`) returns 400.
|
|
726
|
+
|
|
661
727
|
---
|
|
662
728
|
|
|
663
729
|
## Sessions + Chat
|
|
@@ -799,7 +865,7 @@ martha teams add-member refactoring-team ork-1
|
|
|
799
865
|
# Agent side
|
|
800
866
|
export MARTHA_CLIENT_ID=<from above>
|
|
801
867
|
export MARTHA_CLIENT_SECRET=<from above>
|
|
802
|
-
export MARTHA_API_URL=https://martha.
|
|
868
|
+
export MARTHA_API_URL=https://martha.acme.example
|
|
803
869
|
martha auth login --service-account
|
|
804
870
|
martha tasks poll --json # Should return open team-scoped tasks
|
|
805
871
|
```
|
|
@@ -859,6 +925,35 @@ martha integrations specs --json | jq -r '.[] | select(.name == "linear") | .id'
|
|
|
859
925
|
done
|
|
860
926
|
```
|
|
861
927
|
|
|
928
|
+
### Collection hierarchy + scoped grants (#372)
|
|
929
|
+
|
|
930
|
+
```bash
|
|
931
|
+
# See the tree
|
|
932
|
+
martha documents collections --tree
|
|
933
|
+
|
|
934
|
+
# Build a hierarchy
|
|
935
|
+
martha documents create-collection --name "Reports"
|
|
936
|
+
martha documents create-collection --name "2026 Reports" --parent reports
|
|
937
|
+
martha documents create-collection --name "Q1 2026" --parent 2026-reports
|
|
938
|
+
|
|
939
|
+
# Reorganize
|
|
940
|
+
martha documents move-collection q1-2026 --parent reports # promote a level
|
|
941
|
+
martha documents move-collection 2026-reports --root # back to top-level
|
|
942
|
+
|
|
943
|
+
# Scoped grants. Agent only sees docs in /Reports and descendants.
|
|
944
|
+
martha agents add-function planner list_docs --collection reports
|
|
945
|
+
martha agents add-function planner read_doc --collection reports
|
|
946
|
+
|
|
947
|
+
# Most-specific ancestor wins: an additional grant on a child
|
|
948
|
+
# collection overrides config_overrides for that subtree only.
|
|
949
|
+
martha agents add-function planner list_docs --collection q1-2026 --set max_results=50
|
|
950
|
+
|
|
951
|
+
# Revoke just one scope; the parent root grant (if any) survives.
|
|
952
|
+
martha agents remove-function planner list_docs --collection q1-2026
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
`--collection` accepts UUID, slug, or name — same identifier the agent uses. Resolution mirrors the backend.
|
|
956
|
+
|
|
862
957
|
---
|
|
863
958
|
|
|
864
959
|
## Troubleshooting
|