awslabs / awslabs/cli-agent-orchestrator
[Feat] Vault configuration has no authoring surface (memory.vault is read-only through every CLI path)
- Dominant language
- Python
- Stars
- 1.3k
- Forks
- 267
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 70
Description
Follow-up to #644 / #674. The vault knowledge source is fully **configurable** — `memory.vault` in `settings.json`, validated by a pydantic model in `services/vault/config.py` with 20 documented rules — but there is no way to **author** that configuration except opening the file in an editor.
This is a known deferral rather than an oversight: `adr-007-configuration-surface.md` (shipped in #674) decides it and lists the consequences under "Negative, and accepted":
> `set_memory_setting()`'s closed whitelist gains no vault keys. `memory.vault` is a nested object with cross-field invariants (rules 9, 10, 13, 15), which a single-key setter cannot validate. Release one is file-edited, with `cao memory vault status` as the validator.
> **No CLI setter in release one**, so a scripted install must template the file.
> **Hand-editing JSON is a poor authoring experience**, and a trailing-comma typo disables the feature.
Filing so the deferral is tracked rather than implicit, with a proposed shape.
### Measured surface (PR #674 @ `dac2ff8`)
| Surface | Result |
| --- | --- |
| `cao config get memory.vault` | works — returns the whole resolved object |
| `cao config get memory.vault.enabled` | works |
| `cao config list` | lists **both** as known keys |
| `cao config set memory.vault ''` | `Error: Unknown memory setting: vault` |
| `cao config set memory.vault.enabled true` | `Error: Unknown memory setting: vault.enabled` |
| `CAO_MEMORY_VAULT_ENABLED=true` | inert by design — env can only *disable* |
| env var for root / mappings / scopes | does not exist, deliberately |
| `cao memory vault …` | `scan`, `status`, `reconcile`, `rebuild`, `migrate` — no `add`, `init`, `edit`, `remove` |
The security half of that table should stay as it is. ADR-007's reasoning — an env var that could add a mapping "could point CAO at an arbitrary directory and assign it a scope", and a per-repo `.cao/vault.json` would let a cloned repository declare which of the user's vault folders CAO may read and inject — is sound, and nothing below proposes changing it.
### The validator is already the expensive part
Schema errors are keyed and specific, and unknown keys are rejected rather than ignored, so a typo'd `mapping` for `mappings` is caught instead of silently yielding a vault with no mappings:
```
vaults.0.mapping Extra inputs are not permitted
vaults.0.root Value error, root does not exist: /…/nope
vaults.0 Value error, managed_folder must lie inside exactly one writable mapping
```
Anything that can hand a candidate object to `VaultConfig` inherits all 20 rules. That is what makes the increments below small.
### Proposed increments
**1. Message fixes (small, no design debate).**
- [ ] `cao config set memory.vault` reports `Unknown memory setting: vault` one command after `cao config list` printed `memory.vault` as a known key. The CLI contradicts itself, and the natural read of "unknown" is "I typed it wrong." It should state the policy: `memory.vault` is file-edited; see `docs/obsidian-vault.md`.
- [ ] `docs/obsidian-vault.md` says "Add a `memory.vault` object to `settings.json`" without saying that this is the only way, or that `cao config set` will refuse. One sentence closes it.
- [ ] A malformed `settings.json` surfaces as `Error: memory vault is disabled by configuration`, which sends the user to a flag that is in fact `true`; the parse failure is a `logger.warning` above it. ADR-007 offered `status` as the mitigation for hand-editing mistakes, but `status` covers *schema* errors only — a parse error never reaches the schema. (The underlying lenient-load behaviour is not vault-specific and is filed separately.)
**2. `cao config set memory.vault ''`, whole-object only.**
This dissolves ADR-002/007's objection rather than working around it. The stated objection is that *a single-key setter cannot validate cross-field invariants* — true of `memory.vault.vaults[0].mappings[1].scope`, and not true of `memory.vault` itself. Pass the whole object through `VaultConfig` before persisting and an invalid write is refused with the same keyed errors a hand edit gets, so the file can never be left in a state the loader will reject. Concretely: one entry added to `set_memory_setting`'s whitelist, plus validate-before-persist.
This is also what a scripted or containerised install needs — today it has to template raw JSON, which is the case ADR-007 flagged.
**3. `cao memory vault init`, an ergonomic scaffold.**
```bash
cao memory vault init ~/Vaults/Work \
--map 'Notes:global' \
--map 'Projects/CAO:project' \
--managed CAO
```
The strongest justification is deriving the project `scope_id`. Users cannot compute `resolve_project_id` by hand — the demo harness in `examples/obsidian-vault-demo` has to shell out to Python for it — ADR-007 recommends pinning it, and getting it wrong yields a mapping that resolves for nobody: silence, not an error. A command that derives it correctly removes the single most likely misconfiguration. It should end by running the equivalent of `cao memory vault status` so a fresh config is validated in the same breath.
### Explicitly not proposed
- Any env var for paths, mappings, exclusions or scopes (ADR-007 "Env var policy", and rejected alternative C).
- Per-repository vault configuration (rejected alternative D).
- Making the bounds (`max_note_bytes`, `max_notes`, `max_recall_body_chars`) or `secret_gate` settable in bulk — per-mapping granularity is deliberate.
Contributor guide
Research direction
Start with adr-007-configuration-surface.md, services/vault/config.py, the set_memory_setting entry point, and docs/obsidian-vault.md. Run the existing cao config and cao memory vault status commands to observe current behavior and validation. Done means the selected authoring increments are implemented without changing the stated environment-variable or repository-configuration security policy.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100