Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 11 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,62 +315,35 @@ npm install --prefix tools/review-mcp
npm install --prefix integrations/tracevault-mcp
```

Installs `ask_tracevault` — lets agents query indexed session history in natural language ("Why was this refactored?", "What sessions touched the auth service?"). Not required by any policy. Needs `tracevault login` once.
Installs two tools:

- **`ask_tracevault`** — lets agents query indexed session history in natural language ("Why was this refactored?", "What sessions touched the auth service?"). Not required by any policy. Needs `tracevault login` once.
- **`agent_policies`** — returns the rendered policy instructions for the current repo (same output as `tracevault agent-policies`). Call this at session start so the agent's behaviour matches the configured policies.

Claude Code picks up all servers from `.mcp.json` automatically on next session start. No further configuration needed.

## Integrating Visdom Trace into your own project

When you run `tracevault init` in a repository, Visdom Trace installs the session hooks automatically. To get the most out of it — and to make sure your AI agents understand the governance expectationsadd a `CLAUDE.md` to your repo with instructions for the agent.
When you run `tracevault init` in a repository, Visdom Trace installs the session hooks automatically. To make sure your AI agents understand the governance expectations, add a `CLAUDE.md` (or equivalent) entry pointing them at `tracevault agent-policies`.

### Recommended `CLAUDE.md` for a Visdom Trace–integrated project

```
# Visdom Trace session tracking

## During work

Work freely. No special actions needed while coding.

## Pre-push validation

When your work is complete and you are ready to push:

1. Open a validation window — this marks the start of the validation phase:

tracevault validation-start

2. Run all required validation tools. Only tools explicitly allowed by
validation-window policies should be called between this point and push.
The exact tools depend on which policies are configured for this repo.
Check the repo's policy list in the Visdom Trace dashboard.

3. If a validation tool fails and you need to fix the issue, make your fix
and then open a NEW validation window before rerunning the tools:

tracevault validation-start # invalidates the previous window

You must rerun ALL expected validation tools after opening a new window.

4. Once all validation tools have passed, push normally:

git push
Before starting any session, run `tracevault agent-policies` (or call the
`agent_policies` MCP tool if the tracevault MCP is installed) and follow
the instructions it returns. Those instructions reflect the policies
configured on the server and take precedence over anything below.

## Commit messages

Use conventional commits: https://www.conventionalcommits.org/en/v1.0.0/
```

> **Note for project maintainers:** The specific tools required in the validation window (e.g. `mcp__review__agent_review`, `mcp__cargo__cargo_fmt`) depend on the policies configured for your repo in the Visdom Trace dashboard. Add those tool names to the "Run all required validation tools" step above when customising this template for your project.

Adjust the instructions to match your stack. The key behaviors to encode:
`tracevault agent-policies` fetches the active policies from the server and renders Markdown describing which tools must be called, which must succeed, what file patterns trigger conditional checks, and how the validation window works. When policies change in the dashboard, the output updates automatically — you do not need to maintain a manual list in `CLAUDE.md`.

| Instruction | Why |
|---|---|
| Work freely before the validation window | Session-scoped policies can check tools called at any point; Validation-scoped policies only check tools called after `tracevault validation-start` |
| Open validation window when work is done | Marks the start of the pre-push gate phase; only allowed tools should be called between this point and push |
| Restart the window if a fix is needed | `tracevault validation-start` invalidates previous windows; all expected tools must be rerun to satisfy Validation-scoped policies |
| All validation tools must pass before pushing | Policies will block the push if required tools weren't called or didn't succeed |
> **Tool installation:** The rendered instructions reference tools by their literal name (e.g. `mcp__cargo__cargo_fmt`). Make sure those tools are installed in your agent setup. See [Install project-local MCP tools](#4-install-project-local-mcp-tools) for the bundled tools shipped with this repo.

### Policy types you can configure

Expand Down
66 changes: 66 additions & 0 deletions crates/tracevault-cli/src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ pub struct CheckResultItem {
pub details: String,
}

/// Subset of `RepoSettingsResponse` from the server — only the fields we use.
#[derive(Debug, Clone, Deserialize)]
pub struct RepoSettings {
pub validation_window_mode: String,
}

/// Subset of `PolicyResponse` from the server — only the fields we use for rendering.
#[derive(Debug, Clone, Deserialize)]
pub struct PolicyListItem {
#[allow(dead_code)]
pub name: String,
pub condition: serde_json::Value,
pub action: String,
pub scope: String,
pub enabled: bool,
}

#[derive(Debug, Deserialize)]
pub struct RepoListItem {
pub id: uuid::Uuid,
Expand Down Expand Up @@ -272,6 +289,55 @@ impl ApiClient {
Ok(repos)
}

pub async fn list_policies(
&self,
org_slug: &str,
repo_id: &uuid::Uuid,
) -> Result<Vec<PolicyListItem>, Box<dyn Error>> {
let mut builder = self.client.get(format!(
"{}/api/v1/orgs/{}/repos/{}/policies",
self.base_url, org_slug, repo_id
));
if let Some(key) = &self.api_key {
builder = builder.header("Authorization", format!("Bearer {key}"));
}

let resp = builder.send().await?;

if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
return Err(format!("Failed to list policies ({status}): {body}").into());
}

let policies: Vec<PolicyListItem> = resp.json().await?;
Ok(policies)
}

pub async fn get_repo_settings(
&self,
org_slug: &str,
repo_id: &uuid::Uuid,
) -> Result<RepoSettings, Box<dyn Error>> {
let mut builder = self.client.get(format!(
"{}/api/v1/orgs/{}/repos/{}/settings",
self.base_url, org_slug, repo_id
));
if let Some(key) = &self.api_key {
builder = builder.header("Authorization", format!("Bearer {key}"));
}

let resp = builder.send().await?;

if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
return Err(format!("Failed to fetch repo settings ({status}): {body}").into());
}

Ok(resp.json().await?)
}

pub async fn verify_commits(
&self,
org_slug: &str,
Expand Down
Loading
Loading