Skip to content

Commit 98488f9

Browse files
committed
feat: rebrand Oracul to VectorCourt
Rename internal/oracul/ package to internal/vectorcourt/, update auth header to X-VC-Key, default endpoint to vectorcourt.com, config keys to vectorcourt.*, CLI flags to --to vectorcourt / --format vectorcourt, TUI target to VectorCourt. Backward-compat migration reads legacy oracul config keys on load.
1 parent 43b6075 commit 98488f9

15 files changed

Lines changed: 256 additions & 191 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.21.0] - 2026-03-19
6+
7+
### Changed
8+
- Rebrand Oracul to VectorCourt: package `internal/oracul` renamed to `internal/vectorcourt`
9+
- Auth header: `X-Oracul-Key` replaced by `X-VC-Key`
10+
- Default endpoint: `https://oracul.app` replaced by `https://vectorcourt.com`
11+
- Config keys: `oracul.api_key` / `oracul.endpoint` replaced by `vectorcourt.api_key` / `vectorcourt.endpoint`
12+
- CLI flags: `--to oracul` / `--format oracul` replaced by `--to vectorcourt` / `--format vectorcourt`
13+
- TUI: launch target "Oracul Council" renamed to "VectorCourt"
14+
- Backward-compatible config migration: existing `oracul` config keys auto-migrate on load
15+
516
## [0.20.0] - 2026-03-10
617

718
### Added

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ Drag a file into the terminal - VectorPad intercepts the path, classifies the fi
140140
| `stash` | Idea persistence with Jaccard similarity clustering and uniqueness scoring |
141141
| `negativespace` | Negative space detection: flag missing constraint classes in directives |
142142
| `flight` | Flight recorder: append-only launch log with metrics and outcome annotation |
143-
| `oracul` | Oracul API client, sentence-to-CaseFiling mapper, preflight gate |
143+
| `vectorcourt` | VectorCourt API client, sentence-to-CaseFiling mapper, preflight gate |
144144
| `config` | Persistent settings (API keys, endpoints) at `~/.vectorpad/config.json` |
145145
| `detect` | Capability detection for pastewatch and contextspectre binaries |
146146
| `attach` | File attachment pipeline: detect path, classify, preview, serialize |
@@ -169,39 +169,39 @@ See the full [glossary](https://github.com/ppiankov/contextspectre/blob/main/doc
169169

170170
Optional integration with [Pastewatch](https://github.com/ppiankov/pastewatch) scans outbound payloads for secrets before they enter a context window.
171171

172-
## Decision ops: VectorPad + Oracul
172+
## Decision ops: VectorPad + VectorCourt
173173

174-
VectorPad can submit classified cases to [Oracul](https://oracul.app) for multi-model deliberation. Oracul runs a council of models that challenge, strengthen, and split reasoning branches before issuing a verdict artifact.
174+
VectorPad can submit classified cases to [VectorCourt](https://vectorcourt.com) for multi-model deliberation. VectorCourt runs a council of models that challenge, strengthen, and split reasoning branches before issuing a verdict artifact.
175175

176-
**Requires an Oracul API key.** Oracul is a paid service. Get a key at [oracul.app](https://oracul.app).
176+
**Requires a VectorCourt API key.** VectorCourt is a paid service. Get a key at [vectorcourt.com](https://vectorcourt.com).
177177

178178
```bash
179179
# Configure
180-
vectorpad config set oracul.api_key <your-key>
180+
vectorpad config set vectorcourt.api_key <your-key>
181181

182182
# Classify and submit
183-
echo "Should we use Kafka or RabbitMQ?" | vectorpad submit --to oracul
183+
echo "Should we use Kafka or RabbitMQ?" | vectorpad submit --to vectorcourt
184184

185185
# Save verdict as a git-trackable artifact
186186
echo "Should we use Kafka or RabbitMQ? Must handle 10k msgs/sec." \
187-
| vectorpad submit --to oracul --output decisions/message-broker.oracul.json
187+
| vectorpad submit --to vectorcourt --output decisions/message-broker.vectorcourt.json
188188

189189
# Export CaseFiling JSON without submitting (offline, no API key needed)
190-
echo "Should we use Kafka?" | vectorpad export --format oracul
190+
echo "Should we use Kafka?" | vectorpad export --format vectorcourt
191191
```
192192

193-
The submit command classifies your text, maps sentence tags to a structured case filing (CONSTRAINT becomes constraints, DECISION becomes the decision, SPECULATION becomes known risks), runs a preflight check, then sends it to Oracul's `/v1/consult` endpoint.
193+
The submit command classifies your text, maps sentence tags to a structured case filing (CONSTRAINT becomes constraints, DECISION becomes the decision, SPECULATION becomes known risks), runs a preflight check, then sends it to VectorCourt's `/v1/consult` endpoint.
194194

195195
Verdict artifacts are plain JSON. Put them in a `decisions/` directory and commit them alongside the code they affect:
196196

197197
```bash
198-
git add decisions/message-broker.oracul.json
198+
git add decisions/message-broker.vectorcourt.json
199199
git commit -m "decision: message broker selection"
200200
```
201201

202202
`git log decisions/` is your decision history. `git blame` tells you when and why. PRs can include a decision artifact alongside the implementation.
203203

204-
VectorPad is the authoring tool. Oracul is the deliberation engine. Git is the ledger.
204+
VectorPad is the authoring tool. VectorCourt is the deliberation engine. Git is the ledger.
205205

206206
## Known limitations
207207

@@ -219,8 +219,8 @@ VectorPad is the authoring tool. Oracul is the deliberation engine. Git is the l
219219
- [x] Phase 5 - negative space detection, drift timeline in TUI, flight recorder, constraint pinning
220220
- [x] Phase 6 - scope declaration, pressure heat map, vector decomposition, contextspectre feedback loop
221221
- [x] Phase 7 - claim registry (SQLite stash, Ollama embeddings, cosine similarity)
222-
- [x] Phase 8 - Oracul integration (submit, export, config, preflight gate)
223-
- [x] Phase 9 - Oracul TUI experience (account status, launch target, live preflight, verdict stash)
222+
- [x] Phase 8 - VectorCourt integration (submit, export, config, preflight gate)
223+
- [x] Phase 9 - VectorCourt TUI experience (account status, launch target, live preflight, verdict stash)
224224
- [ ] Phase 10 - decision memory (precedent search, async submit, outcome tracking, verdict diff)
225225

226226
## License

cmd/vectorpad/main.go

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"github.com/ppiankov/vectorpad/internal/detect"
1919
"github.com/ppiankov/vectorpad/internal/flight"
2020
"github.com/ppiankov/vectorpad/internal/negativespace"
21-
"github.com/ppiankov/vectorpad/internal/oracul"
21+
"github.com/ppiankov/vectorpad/internal/vectorcourt"
2222
"github.com/ppiankov/vectorpad/internal/preflight"
2323
"github.com/ppiankov/vectorpad/internal/pressure"
2424
"github.com/ppiankov/vectorpad/internal/stash"
@@ -216,14 +216,14 @@ func runLog(args []string, stdout io.Writer, stderr io.Writer) int {
216216
_, _ = fmt.Fprintf(stdout, " %s: %d\n", g.Class, g.Count)
217217
}
218218
}
219-
if stats.Oracul != nil {
219+
if stats.VectorCourt != nil {
220220
_, _ = fmt.Fprintln(stdout, "Oracul:")
221-
_, _ = fmt.Fprintf(stdout, " submits: %d\n", stats.Oracul.TotalSubmits)
222-
_, _ = fmt.Fprintf(stdout, " avg filing quality: %.0f%%\n", stats.Oracul.AvgFilingQuality*100)
223-
_, _ = fmt.Fprintf(stdout, " rejection rate: %.0f%%\n", stats.Oracul.RejectionRate*100)
224-
if len(stats.Oracul.TopWarnings) > 0 {
221+
_, _ = fmt.Fprintf(stdout, " submits: %d\n", stats.VectorCourt.TotalSubmits)
222+
_, _ = fmt.Fprintf(stdout, " avg filing quality: %.0f%%\n", stats.VectorCourt.AvgFilingQuality*100)
223+
_, _ = fmt.Fprintf(stdout, " rejection rate: %.0f%%\n", stats.VectorCourt.RejectionRate*100)
224+
if len(stats.VectorCourt.TopWarnings) > 0 {
225225
_, _ = fmt.Fprintln(stdout, " top warnings:")
226-
for _, w := range stats.Oracul.TopWarnings {
226+
for _, w := range stats.VectorCourt.TopWarnings {
227227
_, _ = fmt.Fprintf(stdout, " %s: %d\n", w.Class, w.Count)
228228
}
229229
}
@@ -743,8 +743,8 @@ func runSubmit(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
743743
}
744744
}
745745

746-
if target != "oracul" {
747-
_, _ = fmt.Fprintln(stderr, "usage: vectorpad submit --to oracul [--output file.json] [--dry-run] [--no-preflight]")
746+
if target != "vectorcourt" {
747+
_, _ = fmt.Fprintln(stderr, "usage: vectorpad submit --to vectorcourt [--output file.json] [--dry-run] [--no-preflight]")
748748
return 1
749749
}
750750

@@ -754,8 +754,8 @@ func runSubmit(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
754754
_, _ = fmt.Fprintf(stderr, "error: %v\n", err)
755755
return 1
756756
}
757-
if cfg.Oracul.APIKey == "" {
758-
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set oracul.api_key <key>)")
757+
if cfg.VectorCourt.APIKey == "" {
758+
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set vectorcourt.api_key <key>)")
759759
return 1
760760
}
761761

@@ -773,10 +773,10 @@ func runSubmit(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
773773

774774
// Classify and map.
775775
sentences := classifier.Classify(text)
776-
filing := oracul.MapSentences(sentences)
777-
question := oracul.ExtractQuestion(sentences, text)
776+
filing := vectorcourt.MapSentences(sentences)
777+
question := vectorcourt.ExtractQuestion(sentences, text)
778778

779-
req := &oracul.ConsultRequest{
779+
req := &vectorcourt.ConsultRequest{
780780
Question: question,
781781
Filing: filing,
782782
}
@@ -792,7 +792,7 @@ func runSubmit(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
792792
return 0
793793
}
794794

795-
client := oracul.NewClient(cfg.Endpoint(), cfg.Oracul.APIKey)
795+
client := vectorcourt.NewClient(cfg.Endpoint(), cfg.VectorCourt.APIKey)
796796

797797
// Preflight gate.
798798
if !noPreflight {
@@ -861,8 +861,8 @@ func runExport(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
861861
}
862862
}
863863

864-
if format != "oracul" {
865-
_, _ = fmt.Fprintln(stderr, "usage: vectorpad export --format oracul")
864+
if format != "vectorcourt" {
865+
_, _ = fmt.Fprintln(stderr, "usage: vectorpad export --format vectorcourt")
866866
return 1
867867
}
868868

@@ -878,10 +878,10 @@ func runExport(args []string, stdin io.Reader, stdout io.Writer, stderr io.Write
878878
}
879879

880880
sentences := classifier.Classify(text)
881-
filing := oracul.MapSentences(sentences)
882-
question := oracul.ExtractQuestion(sentences, text)
881+
filing := vectorcourt.MapSentences(sentences)
882+
question := vectorcourt.ExtractQuestion(sentences, text)
883883

884-
req := &oracul.ConsultRequest{
884+
req := &vectorcourt.ConsultRequest{
885885
Question: question,
886886
Filing: filing,
887887
}
@@ -936,16 +936,16 @@ func runPrecedent(args []string, stdin io.Reader, stdout io.Writer, stderr io.Wr
936936
_, _ = fmt.Fprintf(stderr, "error: %v\n", err)
937937
return 1
938938
}
939-
if cfg.Oracul.APIKey == "" {
940-
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set oracul.api_key <key>)")
939+
if cfg.VectorCourt.APIKey == "" {
940+
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set vectorcourt.api_key <key>)")
941941
return 1
942942
}
943943

944944
// Extract question from classified text.
945945
sentences := classifier.Classify(query)
946-
question := oracul.ExtractQuestion(sentences, query)
946+
question := vectorcourt.ExtractQuestion(sentences, query)
947947

948-
client := oracul.NewClient(cfg.Endpoint(), cfg.Oracul.APIKey)
948+
client := vectorcourt.NewClient(cfg.Endpoint(), cfg.VectorCourt.APIKey)
949949
result, err := client.SearchPrecedents(context.Background(), question, limit)
950950
if err != nil {
951951
_, _ = fmt.Fprintf(stderr, "error: %v\n", err)
@@ -1062,13 +1062,13 @@ func runOutcome(args []string, stdout io.Writer, stderr io.Writer) int {
10621062
_, _ = fmt.Fprintf(stderr, "error: %v\n", err)
10631063
return 1
10641064
}
1065-
if cfg.Oracul.APIKey == "" {
1066-
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set oracul.api_key <key>)")
1065+
if cfg.VectorCourt.APIKey == "" {
1066+
_, _ = fmt.Fprintln(stderr, "error: no API key configured (run: vectorpad config set vectorcourt.api_key <key>)")
10671067
return 1
10681068
}
10691069

1070-
client := oracul.NewClient(cfg.Endpoint(), cfg.Oracul.APIKey)
1071-
resp, err := client.ReportOutcome(context.Background(), envelope.CaseID, &oracul.OutcomeRequest{
1070+
client := vectorcourt.NewClient(cfg.Endpoint(), cfg.VectorCourt.APIKey)
1071+
resp, err := client.ReportOutcome(context.Background(), envelope.CaseID, &vectorcourt.OutcomeRequest{
10721072
Result: result,
10731073
Note: note,
10741074
})

internal/config/config.go

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,29 @@ const (
1616

1717
// Config holds persistent VectorPad settings.
1818
type Config struct {
19-
Oracul OraculConfig `json:"oracul"`
19+
VectorCourt VectorCourtConfig `json:"vectorcourt"`
2020
}
2121

22-
// OraculConfig holds Oracul API integration settings.
23-
type OraculConfig struct {
22+
// VectorCourtConfig holds VectorCourt API integration settings.
23+
type VectorCourtConfig struct {
2424
APIKey string `json:"api_key"`
2525
Endpoint string `json:"endpoint"`
2626
}
2727

28-
// DefaultEndpoint returns the default Oracul API endpoint.
28+
// legacyOraculConfig is used only for reading old config files.
29+
type legacyOraculConfig struct {
30+
APIKey string `json:"api_key"`
31+
Endpoint string `json:"endpoint"`
32+
}
33+
34+
// DefaultEndpoint returns the default VectorCourt API endpoint.
2935
func DefaultEndpoint() string {
30-
return "https://oracul.app"
36+
return "https://vectorcourt.com"
3137
}
3238

3339
// Load reads config from ~/.vectorpad/config.json.
3440
// Returns a zero Config if the file does not exist.
41+
// Migrates legacy "oracul" config keys to "vectorcourt" on read.
3542
func Load() (*Config, error) {
3643
path, err := configPath()
3744
if err != nil {
@@ -50,6 +57,23 @@ func Load() (*Config, error) {
5057
if err := json.Unmarshal(data, &cfg); err != nil {
5158
return nil, fmt.Errorf("parse config: %w", err)
5259
}
60+
61+
// Migrate legacy "oracul" key if "vectorcourt" is empty.
62+
var raw map[string]json.RawMessage
63+
if json.Unmarshal(data, &raw) == nil {
64+
if oraculRaw, ok := raw["oracul"]; ok {
65+
var legacy legacyOraculConfig
66+
if json.Unmarshal(oraculRaw, &legacy) == nil {
67+
if cfg.VectorCourt.APIKey == "" && legacy.APIKey != "" {
68+
cfg.VectorCourt.APIKey = legacy.APIKey
69+
}
70+
if cfg.VectorCourt.Endpoint == "" && legacy.Endpoint != "" {
71+
cfg.VectorCourt.Endpoint = legacy.Endpoint
72+
}
73+
}
74+
}
75+
}
76+
5377
return &cfg, nil
5478
}
5579

@@ -72,18 +96,18 @@ func Save(cfg *Config) error {
7296
return os.WriteFile(path, data, 0600)
7397
}
7498

75-
// Set updates a config value by dot-path key (e.g., "oracul.api_key").
99+
// Set updates a config value by dot-path key (e.g., "vectorcourt.api_key").
76100
func Set(key, value string) error {
77101
cfg, err := Load()
78102
if err != nil {
79103
return err
80104
}
81105

82106
switch key {
83-
case "oracul.api_key":
84-
cfg.Oracul.APIKey = value
85-
case "oracul.endpoint":
86-
cfg.Oracul.Endpoint = value
107+
case "vectorcourt.api_key":
108+
cfg.VectorCourt.APIKey = value
109+
case "vectorcourt.endpoint":
110+
cfg.VectorCourt.Endpoint = value
87111
default:
88112
return fmt.Errorf("unknown config key: %s", key)
89113
}
@@ -99,10 +123,10 @@ func Get(key string) (string, error) {
99123
}
100124

101125
switch key {
102-
case "oracul.api_key":
103-
return cfg.Oracul.APIKey, nil
104-
case "oracul.endpoint":
105-
ep := cfg.Oracul.Endpoint
126+
case "vectorcourt.api_key":
127+
return cfg.VectorCourt.APIKey, nil
128+
case "vectorcourt.endpoint":
129+
ep := cfg.VectorCourt.Endpoint
106130
if ep == "" {
107131
ep = DefaultEndpoint()
108132
}
@@ -112,10 +136,10 @@ func Get(key string) (string, error) {
112136
}
113137
}
114138

115-
// Endpoint returns the configured Oracul endpoint or the default.
139+
// Endpoint returns the configured VectorCourt endpoint or the default.
116140
func (c *Config) Endpoint() string {
117-
if c.Oracul.Endpoint != "" {
118-
return c.Oracul.Endpoint
141+
if c.VectorCourt.Endpoint != "" {
142+
return c.VectorCourt.Endpoint
119143
}
120144
return DefaultEndpoint()
121145
}

0 commit comments

Comments
 (0)