You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today `~/.pramana/config.json` is a single monolithic file holding a flat `{ name → source_dir }` map. This works, but the natural evolution — per-tenant knobs like FTS5 stemmer, embedder choice, source-dir excludes, watch/reload — will nest badly in one file. A file-per-tenant layout scales cleanly.
CLAUDE.md already hints at one of these knobs: "add fts5 stemmer config per tenant" (referenced as an example conventional-commit scope in the repo constitution).
This issue is design-first. Schema and migration are sketched below; implementation is gated on picking a concrete first knob (see "Ordering").
// reserved escape hatch — if set, this tenant runs on a separate daemon
// on this port instead of the shared one. Default (absent) = shared daemon.
// NOT implemented in the first pass; reserved in the schema so future-us
// doesn't migrate again.
"daemon_port": null
}
```
Filename = `.json`. Validated against the existing `^[a-z][a-z0-9-]*$` rule (`config.rs:43-68`). Reserved names unchanged. The `name` field inside the file must match the filename stem (reject mismatch at load time).
`daemon_port` field: on first pass, ignored with a warning if set ("per-tenant daemon ports not yet implemented; this tenant will use the shared daemon"). Reserved for a future issue that builds the per-tenant daemon supervisor.
Broken tenant files: log-and-skip per the silent-drop-warnings policy (separate issue). Don't crash the whole daemon on one malformed file.
Non-goals
Don't build per-tenant daemons now. The `daemon_port` field is a schema reservation; wiring it takes a supervisor, port conflict detection, per-tenant log routing, etc. File a follow-up when someone actually needs it.
Don't source-local the tenant config. Pattern "drop a `.pramana.json` in the source_dir, auto-discover" is tempting but adds ambiguity (which wins: local or central?) and complicates import/export. Keep it central for now.
Don't touch the engine. `TenantConfig` struct gains optional fields; `TenantManager::mount` keeps its shape.
Ordering
This issue is design-first. Do not implement speculatively. Pick it up when:
A concrete need for the first per-tenant knob appears (most likely: FTS5 stemmer, per CLAUDE.md's example). That need drives the issue from design → implementation.
Motivation
Today `~/.pramana/config.json` is a single monolithic file holding a flat `{ name → source_dir }` map. This works, but the natural evolution — per-tenant knobs like FTS5 stemmer, embedder choice, source-dir excludes, watch/reload — will nest badly in one file. A file-per-tenant layout scales cleanly.
CLAUDE.md already hints at one of these knobs: "add fts5 stemmer config per tenant" (referenced as an example conventional-commit scope in the repo constitution).
This issue is design-first. Schema and migration are sketched below; implementation is gated on picking a concrete first knob (see "Ordering").
Target layout
```
~/.pramana/
├── daemon.json # global: port, log level, shared defaults for missing tenant fields
└── tenants/
├── expr-rust.json
├── kastrup.json
└── ggo-learned.json
```
`daemon.json` (new)
```json
{
"version": 1,
"port": 5111,
"log_level": "info",
"defaults": {
"embedder": "all-MiniLM-L6-v2",
"stemmer": "english"
}
}
```
Any field in `defaults` applies to tenants that don't override it.
`tenants/.json`
```json
{
"version": 1,
"name": "expr-rust",
"source_dir": "/abs/path",
// optional — omitted fields inherit from daemon.json.defaults
"embedder": "bge-small",
"stemmer": "english",
"exclude": ["drafts/**", "*.tmp"],
"watch": false,
// reserved escape hatch — if set, this tenant runs on a separate daemon
// on this port instead of the shared one. Default (absent) = shared daemon.
// NOT implemented in the first pass; reserved in the schema so future-us
// doesn't migrate again.
"daemon_port": null
}
```
Filename = `.json`. Validated against the existing `^[a-z][a-z0-9-]*$` rule (`config.rs:43-68`). Reserved names unchanged. The `name` field inside the file must match the filename stem (reject mismatch at load time).
Migration
```
~/.pramana/config.json → ~/.pramana/daemon.json + ~/.pramana/tenants/*.json
```
CLI surface changes
The existing `pramana config` subcommands (`add`, `remove`, `list`, `path`) keep their shape. Behaviour becomes:
Daemon-side changes
Non-goals
Ordering
This issue is design-first. Do not implement speculatively. Pick it up when:
Until then, this issue stays open as the reference doc for the target shape. Label with `enhancement` + whatever "design" label fits.
Acceptance (when picked up)