Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ __pycache__/
# Claude specific exclusions
.claude/

# Miscellaneous git templates and cmds
# Miscellaneous
git/
new_feature_research/

# Never commit secrets (tokens may match GLEAN_* or glean_tok_* patterns)
.env
Expand Down
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,35 @@ For what Glean Code is and how to run it, see the [README](README.md).

### Added

- **Flow mapper (`/flow`)** — a local capture layer that records the investigations you run,
enriches their citations with real document text, and finds the connections between them.
Chat turns group by the `chatId` the API returns, so threading is exact rather than inferred.
Linking runs in three tiers — shared ticket identifiers, shared phrases anchored on document
titles, and cross-session links through a shared or linked document — and every link stores
the evidence for it. `/flow timeline` renders a self-contained HTML timeline with no external
references. Data lives in `~/.gleancode/flow.db` (`0600`), partitioned by instance, mode, and
`act_as` so fictional corpus rows can never link to real tenant content. Capture defaults to
**mock only**; recording live data is opt-in via `flow_capture`, because a local cache has no
permission model. Full guide: [docs/FLOW_MAPPER.md](docs/FLOW_MAPPER.md).
- **`/flow show` draws a rail.** Sessions are nodes on a vertical spine in the order they
happened; a connection branches off it on a yellow `├──◆`, stacking the two documents that
bridge around a `↓` with the evidence that earned the link. Each cited document is tagged with
its datasource in a consistent colour. Colour is decoration only — piped or under `NO_COLOR`
the glyphs still carry the structure — and no line exceeds the terminal width at any size.
`--docs <n>` sets how many documents are listed per session before the rest are counted.
- **`/flow show` orders by what tells you something.** Connections are ranked by kind before
score, because a `shared-citation` link scores `1.00` and says only "you ran this twice"
while the `linked-document` link that found something scores lower — re-running one
investigation used to bury the discovery under a wall of `1.00`s. Documents a thread kept
returning to lead; the rest hold citation order, since sorting by rank interleaves the turns
(every turn's citations restart at rank 0). `--links <n>` caps connections per session.
- **Per-datasource colours** — `ui.DATASOURCE_COLOURS` and `ui.datasource_colour()`, so one
source looks the same wherever it appears. Unknown datasources fall back to grey rather than
being assigned a colour, which would let an unfamiliar source impersonate a familiar one.
- **`width` on `ui.rule()`** — so a block that caps its own columns can draw rules that match.
- **Three more MCP tools** — `get_flow`, `get_flow_summary`, and `get_flow_collapsed` expose the
captured graph to an agent, with the same `[MOCK MODE]` banner and partition rules.
- **`flow_capture` config key** — `mock` (default), `on`, or `off`.
- **`/mcp`** — inspect, configure, and run the bundled MCP server without leaving the REPL.
`/mcp status` reports the installed `mcp` version, whether it can actually run the server,
and any running instance's pid, URL, uptime, and mode. `/mcp config [client]` prints the
Expand All @@ -43,8 +72,16 @@ For what Glean Code is and how to run it, see the [README](README.md).
- **CI workflow renamed** from `tests.yml` to `release.yml`, and it now publishes the built
zipapp as a downloadable workflow artifact.

### Changed

- **`session_links` records both ends of a link** (`to_doc`), and `get_flow_summary` returns the
structured parts — document titles, the shared evidence, and each end's session id — instead
of only a sentence built for a human. Schema version 2; `connect()` migrates an existing
database by adding the column, since `CREATE TABLE IF NOT EXISTS` never reaches one.

### Fixed

- **Mock `/getdocuments` returned no document content.** Real `/getdocuments` returns a body; the mock returned metadata only, which left anything downstream of a citation with nothing to read. It now returns the corpus document's text.
- **`pip install "mcp[cli]"` broke fresh installs.** The MCP SDK's 2.0.0 release renamed
`FastMCP` to `MCPServer` and removed the `mcp.server.fastmcp` module `glean_mcp.py` imports,
so an unpinned install resolved to 2.x and failed on import. Install instructions now pin
Expand Down
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ A local, terminal-first client for the Glean Client REST API. Inspired by Claude
- [Tokens and auth](#tokens-and-auth)
- [Config keys](#config-keys)
- [MCP server](#mcp-server)
- [Flow mapper](#flow-mapper) — map what you have investigated
- [Project layout](#project-layout)
- [Running tests](#running-tests)
- [Documentation](#documentation) — the full reference set
Expand All @@ -57,6 +58,7 @@ A local, terminal-first client for the Glean Client REST API. Inspired by Claude
- **Offline by default** — a real mock corpus of interlinked documents across five faux datasources, so every command is explorable without credentials. See [docs/MOCK_CORPUS.md](docs/MOCK_CORPUS.md)
- **Browser SSO or API token** — `/auth login` runs OAuth 2.1 + PKCE against your instance, or paste a Glean-issued token. Secure refs keep real secrets in environment variables, never on disk
- **MCP server** (`glean_mcp.py`) for Claude Code, Claude Desktop, and Cursor
- **Flow mapper** — `/flow` records the investigations you run, enriches their citations with real text, and finds connections between conversations that never shared context. `/flow show` draws them as a rail with each connection branching off it and the evidence that earned it; `/flow timeline` renders the same graph as a self-contained HTML page. Local SQLite, opt-in for live data. See [docs/FLOW_MAPPER.md](docs/FLOW_MAPPER.md)
- Terminal niceties: `/help <command>` for every command, tab completion that cycles matches, a powerline-style status bar, and `/scaffold` to generate stdlib-only starter projects

## Getting started
Expand Down Expand Up @@ -146,29 +148,11 @@ A native VS Code extension that brings the full Glean Code REPL — slash comman

![Glean Code VS Code extension preview](assets/vscode_extension_glean-code-cli.png)

### Flow Mapper

`/flow` records the investigations you run — every `/chat` and `/search`, and the documents they
cited — then finds the connections between them. Not only the obvious "both mentioned INC-1183",
but the indirect case: two conversations sharing no vocabulary at all, connected because a
document cited by one refers to the other's subject in passing.

Below, a checkout incident and a customer renewal link on `incident, checkout`. Neither
conversation mentions the other. The QBR simply refers to "the checkout incident" in prose —
no ticket number, nothing to join on.

![Flow Mapper preview — /flow show drawing two linked investigations](assets/flow_mapper_preview.png)

Sessions run down a rail in the order you worked; each connection branches off it carrying the
evidence that earned it, so every link can be read rather than taken on trust. Capture is local
SQLite, defaults to recording mock traffic only, and the whole thing works offline against the
built-in corpus — no token needed to try it.

## Commands at a glance

| Area | Commands |
| --- | --- |
| Shell | `/help` `/status` `/doctor` `/auth` `/login` `/logout` `/open` `/ask` `/config` `/mode` `/mcp` `/history` `/clear` `/exit` |
| Shell | `/help` `/status` `/doctor` `/auth` `/login` `/logout` `/open` `/ask` `/config` `/mode` `/mcp` `/flow` `/history` `/clear` `/exit` |
| Chat and search | `/chat` `/search` `/autocomplete` `/recommendations` `/feedback` `/datasources.list` |
| Indexing — read & debug | `/datasources.status` `/datasources.config` `/documents.status` `/documents.count` `/users.count` `/documents.access` `/debug.document` `/debug.documents` `/debug.user` `/indexing.rotate-token` |
| Indexing — single write | `/index.document` `/index.permissions` `/index.user` `/index.group` `/index.membership` and their `/index.delete-*` partners |
Expand Down Expand Up @@ -266,6 +250,20 @@ want a server that isn't owned by a client.

Setup for all three clients, the tool table, and the mock-mode rationale: **[docs/MCP.md](docs/MCP.md)**.

## Flow mapper

`/flow` records the investigations you run — every `/chat` and `/search`, and the documents they cited — then finds the connections between them. Not only the obvious "both mentioned INC-1183", but the indirect case: two conversations sharing no vocabulary at all, connected because a document cited by one refers to the other's subject in passing.

Below, a checkout incident and a customer renewal link on `incident, checkout`. Neither conversation mentions the other. The QBR simply refers to "the checkout incident" in prose — no ticket number, nothing to join on.

![Flow mapper — /flow show drawing two linked investigations](assets/flow_mapper_preview.png)

Sessions run down a rail in the order you worked; each connection branches off it carrying the evidence that earned it, so every link can be read rather than taken on trust. `/flow timeline` renders the same graph as a self-contained HTML page.

Capture is a local SQLite database at `~/.gleancode/flow.db`, partitioned so mock content can never link to real tenant content. It defaults to recording **mock traffic only** — a local cache has no permission model, so recording live data is opt-in via `flow_capture`.

The whole feature works offline against the built-in corpus, with no token. Full guide: **[docs/FLOW_MAPPER.md](docs/FLOW_MAPPER.md)**.

## Project layout

```text
Expand All @@ -280,6 +278,7 @@ glean-code-cli/
config.py config file load and save
help_docs.py per-command documentation
mcp_control.py /mcp — MCP server diagnostics and process control
flow.py /flow — capture, enrich, link, and render investigations
mock_corpus.py the fake corpus every mock endpoint reads from
_indexing_walk.py --path file walking for indexing commands
completion.py readline tab completion
Expand All @@ -288,7 +287,7 @@ glean-code-cli/
auth_commands.py /auth command handlers
auth/ OAuth 2.1 + PKCE: oauth, pkce, callback_server,
token_store, manager
tests/ 17 test modules, stdlib unittest only
tests/ 18 test modules, stdlib unittest only
docs/ full reference set — see below
```

Expand All @@ -313,7 +312,7 @@ files, and they outrank the `Glean Code.app` launcher in `Cmd+Space`:
export PYTHONPYCACHEPREFIX="$HOME/.cache/python"
```

776 tests covering the client and every mock response, commands and dispatch, config, UI, auth, completion, help docs, the mock corpus, indexing-walk, scaffold, the installer, and the MCP server. Development notes: [docs/TESTING.md](docs/TESTING.md).
834 tests covering the client and every mock response, commands and dispatch, config, UI, auth, completion, help docs, the mock corpus, indexing-walk, scaffold, the installer, the MCP server, and the flow mapper. Development notes: [docs/TESTING.md](docs/TESTING.md).

## Documentation

Expand All @@ -328,6 +327,7 @@ export PYTHONPYCACHEPREFIX="$HOME/.cache/python"
| [docs/SSO_OAUTH.md](docs/SSO_OAUTH.md) | Browser SSO via OAuth 2.1 + PKCE |
| [docs/SECURE_TOKENS.md](docs/SECURE_TOKENS.md) | Secure refs, masking matrix, mock-mode fallback |
| [docs/MCP.md](docs/MCP.md) | MCP server setup for Claude Code, Claude Desktop, Cursor |
| [docs/FLOW_MAPPER.md](docs/FLOW_MAPPER.md) | `/flow` — capturing investigations, linking them, and the retention questions |
| [docs/REST_PATHS.md](docs/REST_PATHS.md) | Every REST path this client targets, and how to retarget them |
| [docs/TESTING.md](docs/TESTING.md) | Test-suite development notes |
| [SUPPORT.md](SUPPORT.md) | Best-effort support expectations, triage order, how to file a good bug report |
Expand Down
81 changes: 81 additions & 0 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,87 @@ Inspect, configure, and run the bundled MCP server without leaving the REPL.

---

#### /flow

Map what you have investigated: captured chats, the documents they cited, and the connections between them. Full guide: [docs/FLOW_MAPPER.md](FLOW_MAPPER.md).

```text
/flow <status|enrich|link|show|timeline|purge> [--docs <n>] [--links <n>] [--limit <n>] [--min-score <f>] [--output <file>] [--print] [--all] [--older-than <days>]
```

| Subcommand | Description |
| --- | --- |
| `status` | Capture setting, database path and size, and what has been recorded. The default when no subcommand is given. |
| `enrich` | Fetch document text for captured citations, via `/getdocuments` then `/summarize`. Required before linking. |
| `link` | Find document-to-document and cross-session links. |
| `show` | Draw the captured investigations as a vertical rail, with connections branching off it. |
| `timeline` | Write a self-contained HTML timeline and open it. |
| `purge` | Delete captured data, after confirming. |

| Flag | Description |
| --- | --- |
| `--docs` | `show`: documents listed per session before the rest are counted. Default `6`. |
| `--links` | `show`: connections drawn per session before the rest are counted. Default `3`. |
| `--limit` | `enrich`: documents to fetch in one run. Default `50`. |
| `--min-score` | `link`: phrase-link threshold, 0–1. Default `0.45`. Higher is stricter. |
| `--output` | `timeline`: where to write the HTML. Default a temp file. |
| `--print` | `timeline`: write without opening a browser. |
| `--all` | `purge`: every instance and mode, not just the current one. |
| `--older-than` | `purge`: only sessions older than this many days. |

```text
/flow status
/flow enrich
/flow link --min-score 0.6
/flow show
/flow show --docs 3
/flow timeline --output ~/flow.html
/flow purge --older-than 30
```

**Output** — `show` draws each session as a node on a vertical rail, with its questions, sources, and any connection branching off in yellow:

```text
── flow: acme-be.glean.com · mock ────────────────────────────────────────────

●─ 1 what happened in the checkout incident?
│ Tue 18 Aug 2026, 22:05 · 4 turns · 6 sources
│ ↳ who owned the fix?
│ ▪ confluence Postmortem: Checkout Latency Incident (INC-1183)
│ ▪ slack War room thread: checkout 5xx spike
│ ▪ jira INC-1183 — Elevated 5xx on checkout API
│ … 3 more documents
├──◆ linked-document 0.60 → 2 ───────────────────────────────────────────
│ Postmortem: Checkout Latency Incident (INC-1183)
│ ↓ shares: incident, checkout
│ Customer QBR — Northwind Retail
●─ 2 what are the risks going into the Northwind renewal?
│ Tue 18 Aug 2026, 22:05 · 2 turns · 3 sources
│ ▪ gdrive Customer QBR — Northwind Retail
│ ▪ jira SUP-882 — Northwind: search results missing Confluence…
│ ▪ slack Northwind attachment issue — need connector eyes
──────────────────────────────────────────────────────────────────────────────
```

Documents a thread kept returning to lead the list; the rest hold the order they were cited in. Connections are ordered by how much they tell you — a `linked-document` link found something, while a `shared-citation` link between two runs of the same question is trivially certain and says little — so the discovery is never buried under a wall of `1.00` scores.

Each document is tagged with its datasource in a consistent colour, so a source is recognisable before you read its name. A connection names the session it reaches (`→ 2`), stacks the two documents that bridge around a `↓`, and prints the shared evidence — `shares: incident, checkout` — so every link can be read rather than taken on trust. Colour is decoration only: piped, redirected, or under `NO_COLOR`, the glyphs still carry the structure.

`status` prints a table; `timeline` reports the file written; `purge` confirms before deleting.

**Capture is opt-in for live data.** The `flow_capture` config key defaults to `mock`, so real tenant content is never recorded until you set it to `on`. A local database has no permission model — see [the retention section](FLOW_MAPPER.md#privacy-retention-and-the-parts-to-think-about) before enabling it against a tenant.

**Mock mode** — the built-in corpus is what this feature was tuned against: seven identifier clusters plus a QBR that references an incident in prose with no ticket number, which is the link worth finding.

**Endpoint** — `(local — ~/.gleancode/flow.db; enrich calls /getdocuments or /summarize)`

---

#### /ask

Translate a natural-language request into a sequence of Glean Code slash commands using Glean Assistant as the planner. Read [docs/NATURAL_LANGUAGE.md](NATURAL_LANGUAGE.md) for the full design.
Expand Down
Loading
Loading