refactor(tui): remove hard-coded personal familiars#93
Merged
Conversation
The TUI shipped a roster of seven named built-in familiars (kitty, nova,
cody, charm, sage, astra, echo) with baked-in names, emoji, bespoke
pixel-art, and name-based access grants. A fresh install with no
~/.coven/familiars.toml silently inherited "kitty" as the default, unknown
ids fell back to "kitty", and cody/nova/kitty were auto-granted full
(write/exec) access by name. Other users should never inherit these.
- familiar_theme: drop BUILTIN_PALETTES, builtin(), builtin_access();
reduce Archetype to the four procedural sigils; resolve() now derives
every familiar (roster or unknown) procedurally from its id with no
named fallback.
- mascot: gut to just CompanionPose; remove the seven bespoke art builders,
archetype_lines, and mascot_lines_for.
- familiar_card: route every familiar through the sigil path; add a
pose-driven palette pulse so all cards animate generically.
- app: drop the unwrap_or("kitty") switcher fallback.
- Scrub persona names from test fixtures and update docs/familiars.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Removes hard-coded “personal familiar” personas from the TUI/CLI and shifts rendering entirely to procedurally-derived familiars so fresh installs and unknown IDs no longer inherit named defaults or access tiers.
Changes:
- Deleted built-in familiar palettes/archetypes and bespoke mascot pixel art; rendering is now procedural across the board.
- Updated familiar resolution so unknown IDs derive a theme from the ID itself (no named fallback).
- Scrubbed tests and docs to use neutral example familiar IDs.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src-rust/crates/tui/src/render.rs | Updates tests to use neutral familiar IDs. |
| src-rust/crates/tui/src/mascot.rs | Removes bespoke mascot rendering; retains only pose state used for card animation. |
| src-rust/crates/tui/src/handoff.rs | Updates tests to use neutral familiar IDs/strings. |
| src-rust/crates/tui/src/familiar_theme.rs | Removes built-in roster resolution; resolves themes procedurally and updates tests. |
| src-rust/crates/tui/src/familiar_card.rs | Routes all rendering through procedural sigils; adds pose-driven accent pulsing. |
| src-rust/crates/tui/src/app.rs | Removes kitty fallback in switcher highlighting; updates tests. |
| src-rust/crates/tui/src/agents_view.rs | Updates test fixtures to neutral familiar IDs. |
| src-rust/crates/cli/src/main.rs | Updates tests and fixtures to neutral familiar IDs/branch names. |
| docs/familiars.md | Updates documentation to reflect no built-in roster and procedural glyph behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+216
to
224
| fn unknown_id_is_stable() { | ||
| let a = resolve("solo", &[]); | ||
| let b = resolve("solo", &[]); | ||
| assert_eq!(format!("{:?}", a.archetype), format!("{:?}", b.archetype)); | ||
| assert_eq!( | ||
| format!("{:?}", a.palette.primary), | ||
| format!("{:?}", b.palette.primary) | ||
| ); | ||
| } |
Comment on lines
+241
to
252
| // The eye socket follows each familiar's palette rather than one | ||
| // shared hardcoded violet, so across a spread of ids more than one | ||
| // distinct eye socket shows up. | ||
| let ids = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta"]; | ||
| let sockets: std::collections::HashSet<String> = ids | ||
| .iter() | ||
| .map(|id| format!("{:?}", resolve(id, &[]).palette.eye_socket)) | ||
| .collect(); | ||
| assert!( | ||
| sockets.len() > 1, | ||
| "eye sockets should follow each familiar's palette, got {sockets:?}" | ||
| ); |
Comment on lines
+249
to
+262
| /// Accent color for a sigil's decorative row, pulsed by the companion pose. | ||
| /// | ||
| /// The glyph text never changes width — only the accent row's color shifts | ||
| /// between the bright accent and the dimmer primary — so an `Idle` card | ||
| /// breathes softly and a stalled `Loading` card pulses faster, while a | ||
| /// `Static` card stays bright. This is the only animation; it is identical for | ||
| /// every familiar and tied to no named persona. | ||
| fn pulse_accent(p: &FamiliarPalette, pose: &CompanionPose) -> Color { | ||
| match pose { | ||
| CompanionPose::Idle { frame } if matches!(frame % 120, 90..=95) => p.primary, | ||
| CompanionPose::Loading { frame } if (frame / 5) % 2 == 1 => p.primary, | ||
| _ => p.accent, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The TUI shipped a hard-coded roster of seven named personal familiars —
kitty,nova,cody,charm,sage,astra,echo— each with a baked-in display name, emoji, bespoke pixel-art glyph, and a name-based default tool-access tier. Anyone installing coven-code inherited these:~/.coven/familiars.tomlsilently got "kitty" as the default familiar,kitty, andcody/nova/kittywere auto-grantedfull(write/exec) access by name (a security-relevant inheritance).This removes every aspect of the TUI/CLI that hard-codes those personas, so other users cannot accidentally inherit them in any capacity — while keeping the procedural rendering engine so each user's own
familiars.tomlentries still render with first-class visual identity.Changes
familiar_theme.rs— deletedBUILTIN_PALETTES,builtin(), andbuiltin_access()(the name-basedfull-access grants); reducedArchetypeto the four procedural sigils; rewroteresolve()so roster entries use the user's own definition and any other id is derived procedurally from the id itself — no named fallback.mascot.rs— gutted to justCompanionPose; removed all seven bespoke art builders,archetype_lines, andmascot_lines_for.familiar_card.rs— every familiar now renders through the procedural sigil path; added a pose-drivenpulse_accentso all cards animate generically (no per-persona art).app.rs— removed theunwrap_or("kitty")switcher fallback.app.rs,render.rs,agents_view.rs,handoff.rs,cli/main.rs) scrubbed of persona names → neutralwisp/ember/onyx.docs/familiars.md— replaced the example roster, access-tier role names, opt-in roster example, and example config with generic ids; removed the now-false "Built-in glyphs" table and static-glyph claim.Note: the app-level selection paths (
default_familiar_switcher_list,infer_familiar_from_env,visible_familiar) were already roster-only, andfamiliar_image.rsalready loaded images at runtime from the user's own dirs — those needed no change.Verification
cargo build -p claurst -p claurst-tui— clean.cargo clippy— no new warnings.cargo test -p claurst-tui(632 + suites) and-p claurst— all pass, 0 failures, including the newfamiliar_themeprocedural tests.🤖 Generated with Claude Code