Skip to content

feat: per-agent, per-device import profiles#240

Merged
upsetbit merged 10 commits into
masterfrom
feat/profiles
Jun 12, 2026
Merged

feat: per-agent, per-device import profiles#240
upsetbit merged 10 commits into
masterfrom
feat/profiles

Conversation

@upsetbit

@upsetbit upsetbit commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Why

Each importer only ever read one location per agent (e.g. Codex → ~/.codex/sessions), so sessions from a second CODEX_HOME, workspace, or config dir were invisible. This adds a generic profile concept: a named per-agent, per-device location. Every agent keeps a default profile pointing at its current path, so behaviour is unchanged until you configure more.

What

  • Profile on the canonical session + a profile column on both schemas (local/0009, server/0011, default 'default', indexed by (device_id, agent, profile)) and on the proto Session. No ProjectionVersion bump — the column default backfills existing rows.
  • Generic per-importer location resolution: new Importer.RootsUnder(base) lets each importer derive its own scan subpath from a profile's home dir (codex→/sessions, claude→/projects, …). No Codex-specific code in the sync/config layers.
  • Local config profiles.json (internal/profiles) — the name→path registry; only the name is pushed to the server.
  • CLI: prosa profiles list | add | remove | set-path and a global --profile filter (timeline, search, analytics; local + remote).
  • Server: push/list/search/get/children carry and filter by profile; new profiles analytics report (device × agent × profile).
  • Panel: profile multi-select facet, a Profile row in session detail, and a /profiles breakdown page.

Decisions

Question Choice
Profile path points to the agent home dir (CODEX_HOME-style); the importer appends its subpath
Registry local profiles.json + a profile name column on sessions (no DB table)
UI scope full panel: facet + detail + breakdown page
Same session id in two profiles tag-onlyid stays the global PK; raw paths unchanged

Compatibility

  • No profiles.json → only the synthesized default → identical to today.
  • Existing rows / older clients → default via the column default.
  • Re-tagging an already-imported session (moving its dir) needs prosa sync --overwrite (the raw hash is unchanged otherwise).

Verification

just gen-check, vet, golangci-lint, test-race, lint-md, tidy-check, and the CLI integration test all pass. Verified end-to-end: a configured work profile imports from its own dir, sessions are tagged, --profile work/--profile default filter correctly, and analytics profiles shows the device × agent × profile breakdown.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

upsetbit and others added 10 commits June 11, 2026 03:07
Add Session.Profile with the DefaultProfile constant and ProfileOrDefault
helper, plus a profile field on the wire Session, ListRequest, and
SearchRequest messages (regenerated). Empty normalises to "default", so
existing rows and older clients keep working; no projection bump is needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add RootsUnder(base) to the Importer contract so each importer derives its
own scan subpath from a profile's base directory; DefaultRoots now delegates
to it. ImportOptions.Profile carries the source profile, which the shared
single-file helper and the bespoke Hermes path stamp onto each session.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Local migration 0009 adds sessions.profile (default 'default') plus a
(device_id, agent, profile) index. Read and write the column, filter
ListSessions by profile, and add ProfileCounts plus the analytics
"profiles" report.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Server migration 0011 mirrors the local column. Push upserts it; List,
Search, Get, and ListChildren select, group, scan, and filter by profile
(single and multi-select), and a new "profiles" analytics report breaks
sessions down by device, agent, and profile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New internal/profiles config (profiles.json) resolves each agent's effective
profiles: a synthesized default plus configured extras. prosa profiles
list/add/remove/set-path manages them; sync threads the per-profile name
into each import; and a global --profile filter narrows the timeline,
search, and analytics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a profile multi-select to the Sessions filter, a Profile row in the
session side panel, and a /profiles breakdown page (device x agent x
profile) linking into filtered session views.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update INTENT, the importer/canonical-session/store/cli architecture docs,
the Codex source notes (CODEX_HOME example), and the usage guide for the
profiles concept, the prosa profiles command, and the --profile filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Trim the profiles feature's comments to the repo's sparse style: drop
narration of self-evident code and compress multi-line docstrings to one
or two lines. No behaviour change. gen/ regenerated from the trimmed proto.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…36.0

The committed file was generated by a newer protoc-gen-go than the
v1.36.0 pinned in .justfile, so CI's gen-check (which regenerates with
the pinned toolchain) saw a diff and failed. Regenerate with v1.36.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	internal/server/handlers/analytics.go
@upsetbit upsetbit merged commit fd07c17 into master Jun 12, 2026
5 checks passed
@upsetbit upsetbit deleted the feat/profiles branch June 15, 2026 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant