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
2 changes: 1 addition & 1 deletion .agent/context/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Domain terms specific to Aura. Add as you encounter unfamiliar terminology.

## Terms

**Agent** — an AI coding assistant whose usage Aura monitors. Currently: Claude Code, Codex. Future: custom command agents.
**Agent** — an AI coding assistant whose usage Aura monitors. Currently: Claude Code, Codex, Gemini, Antigravity. Future: custom command agents.

**Agent profile** — a named configuration entry pointing at a specific agent kind and config path. One user can have multiple profiles for the same agent kind (e.g., personal vs. enterprise).

Expand Down
34 changes: 34 additions & 0 deletions .agent/context/stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@ Periodic rollup. Stale by months in practice (observed: last updated 2026-02-16

_No `claude usage` CLI subcommand exists._

## Antigravity data source

Two sources, neither of them shaped like the others.

**Activity:** `~/.gemini/antigravity-cli/conversation_summaries.db` — SQLite,
one row per conversation (`step_count`, `last_modified_time`,
`last_user_input_time`, `app_data_dir`). Covers both the CLI and the
Antigravity IDE; Aura counts every row. Opened read-only through a
`file:…?mode=ro` URI so a running `agy` is never blocked, falling back to
`immutable=1` when the `-shm` file can't be created.

**Quota:** `agy -p "/usage" --output-format json`, a documented public flag.
The slash command is answered locally from a cached backend reading, so it
starts no LLM turn and consumes no quota; it costs ~3 s of Go-binary startup,
which a 20 s TTL cache absorbs. The underlying RPC
(`v1internal:retrieveUserQuotaSummary`) is not usable directly: `agy` keeps
its OAuth token in the OS keyring and the call is license-gated on the CLI's
own client identity.

_No token counts are recoverable._ The trajectories in
`conversations/<uuid>.db` are schema-less protobuf with no plaintext model
names, so `UsageSnapshot::tokens_unreported` marks the token fields absent
rather than zero.

## Plugin loading

**Subprocess + JSON IPC** — Aura spawns the plugin binary and reads a JSON panel payload from stdout. Any language can author plugins. 500ms timeout; plugins that exceed it are shown in an error state.
Expand All @@ -55,6 +79,16 @@ _No `claude usage` CLI subcommand exists._

`serde` + `toml` for config; `serde` + `serde_json` for state persistence and plugin IPC.

## SQLite

`diesel` (sqlite backend, no default features) with `libsqlite3-sys/bundled`, for
Antigravity's `conversation_summaries.db`. Bundled so no host `libsqlite3` is
required on any release target. Five of the six build natively; only
`aarch64-pc-windows-msvc` cross-compiles, on an x86_64 `windows-latest` runner
that carries `Microsoft.VisualStudio.Component.VC.Tools.ARM64` — and that
target is already `experimental: true`. The workspace already compiles C
(`cc` arrives via the gpui tree), so this adds no new class of dependency.

## Error handling

`anyhow` for binary crates; `thiserror` for library crates.
2 changes: 2 additions & 0 deletions .design/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Source: `crates/aura/src/app.rs:25-27` and `app.rs:848-862`.
| `AgentKind::ClaudeCode` | `#d97757` | Anthropic's published Claude orange. | `app.rs:854` |
| `AgentKind::Codex` | `#ffffff` | OpenAI's pure-white mark — **needs fallback**. | `app.rs:855` |
| `AgentKind::Gemini` | `#4285f4` | Google Blue — readable as-is on dark surfaces. | `app.rs:856` |
| `AgentKind::Antigravity` | `#7c5cff` | The mark is a monochrome arc with no brand color to borrow; violet keeps it distinct from the Google blue beside it. | `theme.rs:248` |

## The luminance fallback rule

Expand Down Expand Up @@ -56,6 +57,7 @@ fn agent_accent(kind: AgentKind) -> u32 {
AgentKind::ClaudeCode => COLOR_CLAUDE, // 0xd97757
AgentKind::Codex => COLOR_OPENAI, // 0xffffff
AgentKind::Gemini => COLOR_GEMINI, // 0x4285f4
AgentKind::Antigravity => COLOR_ANTIGRAVITY, // 0x7c5cff
};
if relative_luminance(brand) > 0.85 {
0xb8b8c0
Expand Down
46 changes: 46 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# CodeQL configuration for Aura.
#
# Read by `github/codeql-action/init` via `config-file:` in
# .github/workflows/codeql-analysis.yml.
#
# Why `paths-ignore` works here: CodeQL analyses Rust with build mode `none`,
# building its database without compiling the crate. `paths` / `paths-ignore`
# apply to an interpreted language, or to a compiled language analysed without
# a build — which is this case. They would be silently ignored if CodeQL were
# tracing a real `cargo build`.

name: Aura CodeQL config

paths-ignore:
# Vendored third-party source. `vendor/gpui` is a patched copy of Zed's
# gpui, carried so we can keep the macOS 26 (Tahoe) NSApplication fix —
# see the `[patch.crates-io]` note in Cargo.toml. We do not author it and
# cannot act on findings inside it, so scanning it only produces alerts
# nobody can close: today that is a standing `rust/access-invalid-pointer`
# in `platform/windows/platform.rs`.
- vendor

query-filters:
# `rust/cleartext-logging` fires on `aura quota`'s output. `ClaudeOauth`
# (deserialised from ~/.claude/.credentials.json, quota/oauth.rs) holds
# `access_token` and `refresh_token` in the same struct as
# `subscription_type`, and CodeQL's taint tracking is field-insensitive —
# so any field of that struct reaching a print is flagged. The only value
# that actually reaches stdout is the plan tier ("pro" / "max"), via
# `QuotaSnapshot::subscription_type` (quota/api.rs:221). The tokens are
# used solely to build the authorization header (quota/api.rs:144) and
# never enter `QuotaSnapshot`.
#
# CAUTION: this exclusion is repo-wide. CodeQL has no path-scoped rule
# filter, and Rust has no inline `// codeql[...]` suppression
# (github/codeql#21637), so there is no way to scope it to the three
# `println!`s that prompted it. It therefore also silences a *genuine*
# future leak — which matters in a process that holds live OAuth
# credentials for four agents.
#
# The narrower control is per-alert dismissal in the Security tab, which
# is already in place for alerts 5, 6 and 7 and persists on its own. If
# you would rather keep the rule armed, delete this `query-filters` block;
# nothing else depends on it.
- exclude:
id: rust/cleartext-logging
1 change: 1 addition & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/codeql-config.yml

# GPUI + tray-icon (gtk) link GTK / xkbcommon / xcb / fontconfig
# via pkg-config; the build script panics without dev headers.
Expand Down
156 changes: 154 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ anyhow = "1"
chrono = { version = "0.4", default-features = false, features = ["std", "clock", "serde", "unstable-locales"] }
clap = { version = "4", features = ["derive", "wrap_help"] }
clap_complete = "4"
# Antigravity keeps its conversation summaries in a SQLite DB
# (`~/.gemini/antigravity-cli/conversation_summaries.db`) rather than JSONL.
# `libsqlite3-sys/bundled` compiles the amalgamation in-tree so no host
# libsqlite3 is required on any of the six release targets.
diesel = { version = "2.3", default-features = false, features = ["sqlite"] }
dirs = "7"
libsqlite3-sys = { version = "0.38", features = ["bundled"] }
notify-debouncer-mini = "0.7"
semver = { version = "1", features = ["serde"] }
serde = { version = "1", features = ["derive"] }
Expand Down
Loading