feat(build): user-agnostic personalized variant routing

Personalized variants (default trigger: salva.md) compile to a separate
top-level folder so generated/<persona>/ stays clean of per-user content.
Both the trigger variant filename(s) and the output folder name are
config-driven via config.user — the build is truly user-agnostic.

Build changes:
- Module-level _RUNTIME dict cached by configure_runtime(config) at startup
- resolve_personalized_variants(config) — config.user.personalized_variants
- resolve_personalized_output_dirname(config) — slug-derives from
  user.name (e.g. "Salva" → "salva-personas") with explicit override key
- resolve_personalized_source_dirname(config) — defaults to literal
  "personalized" (gitignorable, user-name-independent)
- iter_persona_output_dirs() — single helper used by all install_*()
  functions to transparently iterate both layouts
- build_persona() routes salva variants based on _RUNTIME at write time
- build_skills_index() also scans <repo>/personalized/skills/ so personal
  skills (with user-private data) merge into the shared skill index
- main() picks up persona dirs from BOTH personas/ and personalized/

New config keys (all optional):
- user.personalized_variants
- user.personalized_output_folder
- user.personalized_source_folder

Output layout (e.g. for user.name="Salva"):
- generated/<persona>/general.{json,yaml,prompt.md}     (shared)
- generated/<persona>/<spec>.{json,yaml,prompt.md}      (shared)
- generated/salva-personas/<persona>/salva.{json,yaml,prompt.md}  (private)

Source layout:
- personas/<persona>/general.md, <spec>.md              (committed)
- personalized/<persona>/salva.md                       (gitignored)
- personalized/skills/<skill>/SKILL.md                  (gitignored)
- personalized/_user_context.md                         (gitignored)

Adds /personalized/ to .gitignore. Documents the new layout in CLAUDE.md
and README.md. Maps linkedin-content-strategy → herald/forge/frodo/ghost
in the default skill persona map.
This commit is contained in:
salvacybersec
2026-05-07 16:49:01 +03:00
parent 1161e69f51
commit cbb28903fb
6 changed files with 272 additions and 53 deletions

View File

@@ -222,11 +222,14 @@ sources/
### Variant Types
| Type | Purpose | Example |
|------|---------|---------|
| `general.md` | Base persona — works standalone for any user | `neo/general.md` |
| `<specialization>.md` | Domain deep-dive narrowing the persona's focus | `neo/redteam.md` |
| `salva.md` | User-personalized — references specific projects, data, tools | `neo/salva.md` |
| Type | Purpose | Example | Output location |
|------|---------|---------|-----------------|
| `general.md` | Base persona — works standalone for any user | `neo/general.md` | `generated/<persona>/` |
| `<specialization>.md` | Domain deep-dive narrowing the persona's focus | `neo/redteam.md` | `generated/<persona>/` |
| `salva.md` (personalized) | User-personalized — references specific projects, data, tools | `neo/salva.md` | `generated/<user-slug>-personas/<persona>/` |
**Personalized variant routing (config-driven, user-agnostic):**
The build keeps user-specific output in a separate top-level folder so the main `generated/<persona>/` directories stay clean. The folder name is derived from `config.user.name` (slugified, `-personas` suffix) — e.g. `user.name: "Salva"``generated/salva-personas/<persona>/salva.*`. Both the trigger variant filename(s) and the output folder name are overridable via `config.user.personalized_variants` / `config.user.personalized_output_folder`. Defaults preserve the historical `salva.md` convention.
## Prompt Format