diff --git a/commands/scout-profile.md b/commands/scout-profile.md new file mode 100644 index 0000000..4728825 --- /dev/null +++ b/commands/scout-profile.md @@ -0,0 +1,66 @@ +--- +name: scout-profile +description: Review and fill in your Scout user profile — only asks about what's still missing. Use after an upgrade to populate the new profile files, or anytime to refine how Scout communicates with you and what your goals are. +--- + +# Scout Profile + +You help {{USER_NAME}} fill in their Scout user profile. This is a **gap-filling** interview: it asks **only** about information that is still missing, never re-asks what's already set, and never overwrites the user's own edits or Scout-derived values. Safe to run repeatedly — it converges. + +The profile lives in `~/Scout/knowledge-base/profile/`: +- `about-you.md` — identity + what Scout has derived about you (mostly self-maintained) +- `communication.md` — how Scout talks to you (the part Scout can't derive) +- `goals.md` — your goals, used as a prioritization lens + +--- + +## Step 0: Pre-flight + +```bash +test -f "$HOME/Scout/scout-config.yaml" && echo "VAULT_OK" || echo "NO_VAULT" +test -d "$HOME/Scout/knowledge-base/profile" && echo "PROFILE_OK" || echo "PROFILE_MISSING" +``` + +- `NO_VAULT`: "No Scout vault found. Run `/scout-setup` first." Stop. +- `PROFILE_MISSING`: the profile files predate this feature. Tell the user: "Your vault doesn't have profile files yet — run `/scout-update` once to seed them, then re-run `/scout-profile`." Stop. +- Both OK: continue. + +## Step 1: Detect gaps + +Read all three files. A field is a **gap** if it still contains its `` sentinel or is empty. Anything else — a value the user typed, or a Scout-derived line (it carries a confidence tag or sits under a derived section) — is **not** a gap. Build the list of gaps across: + +- `communication.md`: language, tone, length, notification cadence, escalation ("always check first" / "safe to handle"), don'ts +- `about-you.md`: role/title, employer/team (these Scout can also derive — only ask if the user wants to set them explicitly) +- `goals.md`: any **Proposed (unconfirmed)** goals Scout has drafted that are awaiting a confirm/edit/drop decision + +If there are **no gaps**, tell the user the profile is complete and show a one-line summary of what's set. Stop. + +## Step 2: Interview — only the gaps + +Ask about the gaps **one at a time**, in this priority order (highest-value first): communication contract → unconfirmed goals → optional identity fields. Each question is **skippable** — make that explicit ("press Enter to skip; Scout will keep the default / derive it / ask again later"). + +For unconfirmed goals, present each proposed goal with the evidence Scout based it on and ask: confirm / edit / drop. + +Do not ask about things Scout derives well on its own (key people, current focus, working rhythm) — those are not gaps to interview, they fill in from connector activity. + +## Step 3: Write — fill only, never clobber + +For each answered question, edit the live file: +- Replace **only** the matching `` sentinel with the user's words. Never touch a line that isn't a sentinel. +- For confirmed goals, move the item from **Proposed (unconfirmed)** to **Confirmed goals** with a one-line Why + horizon; for dropped ones, delete the proposal. +- Skipped questions: leave the sentinel in place. +- Bump `last_reviewed:` to today in any file you changed. + +Do not invent values beyond what the user said. + +## Step 4: Offer an immediate backfill (optional) + +So the user sees results now instead of waiting for the next scheduled run, offer: "Want me to run Scout now so it derives the rest of your profile (key people, current focus, goal candidates) from your connectors?" + +If yes: + +```bash +SCOUT_FORCE_MODE=morning-briefing ~/Scout/run-scout.sh +``` + +If no: "Done — Scout will fill in the derived parts on its next scheduled run." Report which fields were set and which were left for Scout to derive or to ask again later. diff --git a/commands/scout-setup.md b/commands/scout-setup.md index dd06f3e..ca89758 100644 --- a/commands/scout-setup.md +++ b/commands/scout-setup.md @@ -70,6 +70,9 @@ Ask each of these in order, waiting for each answer: 2. "What's your name? (used in commit messages and the KB)" 3. "What's your email? (used for git config)" 4. "Timezone? (default: America/New_York)" +5. **(Optional, skippable)** "How would you like Scout to communicate with you — preferred language, tone/length, and anything it should always check with you before acting on? (Press Enter to skip — Scout fills this from defaults and learns the rest from your feedback. You can set it anytime with `/scout-profile`.)" + +Capture the answer to #5 verbatim (or empty if skipped) for Step 3c. Everything else about the user — role, key people, focus, goals — Scout derives from your connectors on its own runs; do **not** ask for them here. --- @@ -171,6 +174,20 @@ Set `ENABLED = True` if the user said yes, `False` if they said no. --- +## Step 3c: Seed the communication contract (only if the user answered Q5) + +If the user **skipped** Q5, do nothing here — the seeded `communication.md` defaults stand and Scout learns from feedback. + +If they **answered**, open `~/Scout/knowledge-base/profile/communication.md` (already seeded by bootstrap) and fill in only the fields their answer covers, by replacing the matching `` sentinel(s): + +- preferred language → the **Language** line +- tone / length → the **Tone & length** lines +- what to always check first → the **Always check with {{USER_NAME}} first** line under the autonomy contract + +Leave every sentinel they didn't address untouched (Scout fills those from feedback later). Do not invent preferences beyond what they said. Then bump `last_reviewed:` to today. This is the same "post-write into the freshly-created vault" pattern as Step 3b — edit the live file directly; the template is not re-rendered at install time. + +--- + ## Step 4: Report and offer first-run Report the result to the user: diff --git a/commands/scout-update.md b/commands/scout-update.md index 7d463e3..9c09191 100644 --- a/commands/scout-update.md +++ b/commands/scout-update.md @@ -148,6 +148,8 @@ If runner backups appeared (`run-*.sh.bak.*`), tell the user the live runners ha - `~/Scout/connector-probes.local.yaml` (custom connector probes) is a user file, never templated, so it is preserved untouched across upgrades. +**New profile files.** If this upgrade seeded `knowledge-base/profile/` for the first time (check: the files exist now and `plugin.applied_migrations` includes `profile-files-v1`), tell the user once: "Scout now keeps a user profile — it derives most of it (who you are, who matters, your focus) on its runs. To set how Scout talks to you and confirm your goals, run `/scout-profile`." + --- ## Auto-update nudge diff --git a/engine/scout/scripts/bootstrap.py b/engine/scout/scripts/bootstrap.py index 8659e99..449ab4a 100644 --- a/engine/scout/scripts/bootstrap.py +++ b/engine/scout/scripts/bootstrap.py @@ -82,6 +82,7 @@ class MigrateLegacyResult: "knowledge-base/projects", "knowledge-base/ontology/entities", "knowledge-base/people", + "knowledge-base/profile", "knowledge-base/personal", "knowledge-base/recurring-tasks", "action-items/archive", @@ -126,13 +127,28 @@ class MigrateLegacyResult: _INSTALL_ONLY_TEMPLATES = ( # Vault-owned files seeded once on install (cat 2). Never overwritten on upgrade. + # Idempotent: _stage_install_only_seeds skips any file that already exists, so + # this tuple is safe to replay on upgrade — which is how existing vaults pick + # up newly-added seeds (e.g. the profile files) without clobbering edits. ("dreaming-proposals.md", "templates/dreaming-proposals.md.tmpl"), ("knowledge-base/scout-mistake-audit.md", "templates/scout-mistake-audit.md.tmpl"), ("knowledge-base/review-queue.md", "templates/review-queue.md.tmpl"), ("inbox.md", "templates/inbox.md.tmpl"), ("meetings/meetings.md", "templates/meetings/meetings.md.tmpl"), + # User profile: a Scout-maintained "about you" snapshot, a communication + # contract, and a goals file used as a prioritization lens. Seeded as + # editable stubs; Scout derives/refines the rest. See phases/core/00-about-you.md. + ("knowledge-base/profile/about-you.md", "templates/knowledge-base/profile/about-you.md.tmpl"), + ("knowledge-base/profile/communication.md", "templates/knowledge-base/profile/communication.md.tmpl"), + ("knowledge-base/profile/goals.md", "templates/knowledge-base/profile/goals.md.tmpl"), ) +# Marker recorded in scout-config.yaml `plugin.applied_migrations` once the +# profile seeds have been replayed on an existing vault, so the upgrade path is +# observable (and so a future cleanup could gate on it). The seed itself is +# idempotent regardless of this marker. +_PROFILE_SEED_MIGRATION = "profile-files-v1" + _CAT1B_RUNNERS = ( ("run-scout.sh", "templates/run-scout.sh.tmpl"), ("run-dreaming.sh", "templates/run-dreaming.sh.tmpl"), @@ -513,7 +529,12 @@ def _stage_version_stamp(cfg: BootstrapConfig, *, is_upgrade: bool) -> None: # permanently red. plugin.setdefault("version_at_last_setup", cfg.plugin_version) plugin["version_at_last_update"] = cfg.plugin_version - plugin.setdefault("applied_migrations", []) + migrations = plugin.setdefault("applied_migrations", []) + # Record the profile-seed migration once the seeds have been written + # (install always seeds; upgrade replays the idempotent seeder). Makes the + # profile rollout observable in scout-config.yaml without re-running work. + if _PROFILE_SEED_MIGRATION not in migrations: + migrations.append(_PROFILE_SEED_MIGRATION) _atomic_write(config_path, yaml.safe_dump(existing, sort_keys=False)) @@ -614,6 +635,11 @@ def upgrade(cfg: BootstrapConfig) -> UpgradeResult: # no-ops on vaults that are already per-file or never had legacy files. _stage_migrations(cfg) _stage_cat1_writes(cfg) + # Replay install-only seeds so existing vaults pick up newly-added + # cat-2 files (e.g. the profile/ files). Idempotent: every seed skips + # a target that already exists, so user edits are never clobbered and + # files seeded on a prior install/upgrade are left untouched. + _stage_install_only_seeds(cfg) # _stage_seed_schedule is idempotent (returns early if the file # exists) so it's safe to call on upgrade. Without it, vaults set # up before .scout-state/schedule.yaml was a first-class file diff --git a/engine/tests/unit/test_profile_seed.py b/engine/tests/unit/test_profile_seed.py new file mode 100644 index 0000000..301f194 --- /dev/null +++ b/engine/tests/unit/test_profile_seed.py @@ -0,0 +1,114 @@ +"""Unit tests for the user-profile feature: profile-file seeding (install + +upgrade), edit preservation, migration recording, and that the profile phases +land in the assembled brain files.""" + +from __future__ import annotations + +import shutil +from pathlib import Path + +import yaml + +from scout.scripts.bootstrap import _PROFILE_SEED_MIGRATION, install, upgrade +from tests.unit.test_bootstrap_upgrade import _config + +_PROFILE_FILES = ( + "knowledge-base/profile/about-you.md", + "knowledge-base/profile/communication.md", + "knowledge-base/profile/goals.md", +) + + +def _plugin() -> Path: + return Path(__file__).parent.parent.parent.parent + + +def test_install_seeds_profile_files_rendered(tmp_path): + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + + for rel in _PROFILE_FILES: + assert (vault / rel).exists(), f"{rel} not seeded on install" + + about = (vault / "knowledge-base/profile/about-you.md").read_text() + assert "Test User" in about # {{USER_NAME}} rendered + assert "America/New_York" in about # {{TIMEZONE}} rendered + assert "test@example.com" in about # {{USER_EMAIL}} rendered + assert "{{" not in about, "unrendered template marker left in seeded file" + + +def test_profile_files_are_invisible_to_ontology_parser(tmp_path): + """Profile notes must NOT carry a `type:` — otherwise the ontology parser + ingests them and validate() flags 'Unknown entity type'. They use `kind:`.""" + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + for rel in _PROFILE_FILES: + fm = (vault / rel).read_text().split("---", 2)[1] + meta = yaml.safe_load(fm) + assert "type" not in meta, f"{rel} has a `type:` — parser will validate it" + assert meta.get("kind") == "profile" + + +def test_upgrade_seeds_profile_on_existing_vault(tmp_path): + """A vault that predates the profile feature picks up the files on upgrade.""" + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + + # Simulate a pre-feature vault: no profile dir at all. + shutil.rmtree(vault / "knowledge-base/profile") + assert not (vault / "knowledge-base/profile").exists() + + cfg = _config(vault, plugin_root=_plugin()) + cfg.plugin_version = "0.4.1" + upgrade(cfg) + + for rel in _PROFILE_FILES: + assert (vault / rel).exists(), f"{rel} not re-seeded on upgrade" + + +def test_upgrade_preserves_profile_edit(tmp_path): + """An existing profile file is never clobbered on upgrade (cat-2 seed).""" + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + + comm = vault / "knowledge-base/profile/communication.md" + comm.write_text(comm.read_text() + "\n- Reply in Czech, terse bullets.\n") + + cfg = _config(vault, plugin_root=_plugin()) + cfg.plugin_version = "0.4.1" + upgrade(cfg) + + assert "Reply in Czech, terse bullets." in comm.read_text(), "profile edit clobbered" + + +def test_profile_migration_recorded_and_idempotent(tmp_path): + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + + cfg_path = vault / "scout-config.yaml" + migs = yaml.safe_load(cfg_path.read_text())["plugin"]["applied_migrations"] + assert migs.count(_PROFILE_SEED_MIGRATION) == 1, "marker missing/duplicated on install" + + cfg = _config(vault, plugin_root=_plugin()) + cfg.plugin_version = "0.4.1" + upgrade(cfg) + migs2 = yaml.safe_load(cfg_path.read_text())["plugin"]["applied_migrations"] + assert migs2.count(_PROFILE_SEED_MIGRATION) == 1, "marker duplicated on upgrade" + + +def test_profile_phases_land_in_assembled_brain_files(tmp_path): + vault = tmp_path / "Scout" + install(_config(vault, plugin_root=_plugin())) + + skill = (vault / "SKILL.md").read_text() + dreaming = (vault / "DREAMING.md").read_text() + research = (vault / "RESEARCH.md").read_text() + + # 00-about-you has empty mode → present in every target. + for content in (skill, dreaming, research): + assert "profile/about-you.md" in content + + # relationships is mode:[briefing] → SKILL only (briefing/consolidation target). + assert "Relationship Maintenance" in skill + assert "Relationship Maintenance" not in dreaming + assert "Relationship Maintenance" not in research diff --git a/phases/connectors/claude-sessions.md b/phases/connectors/claude-sessions.md index 9ac437a..7dedb0d 100644 --- a/phases/connectors/claude-sessions.md +++ b/phases/connectors/claude-sessions.md @@ -78,3 +78,11 @@ Narrate the deltas in the run summary, and surface an instance-owned PR that's o ### Claim Gate — No "Actively Building X" Without a Cited Signal Do not assert that {{USER_NAME}} "is actively building / working on X" unless you can cite a concrete signal: a session JSONL with matching prompts, a commit SHA, an open PR, or dirty working-tree files. A session *title* or a single prompt is weak evidence — tie the claim to the tangible artifact, or downgrade it to "{{USER_NAME}} opened a session about X" rather than asserting active work. + +### Profile Signal — Feed `knowledge-base/profile/` + +Your own sessions are a uniquely good source for the user profile, because they show how {{USER_NAME}} actually works and writes — something the inbound connectors can't see. Stays local (`cc-session-cache` summaries); nothing leaves the machine. While scanning, also harvest, with the same confidence discipline as everywhere else: + +- **Identity & focus → `profile/about-you.md`:** recurring projects, domains, and tools across sessions sharpen the "current focus" and role/team fields. Tag inferred claims `[single-source]` until corroborated. +- **Communication style → `profile/communication.md`:** the language {{USER_NAME}} writes in and the way they phrase requests (terse vs. narrative, direct vs. exploratory) are a strong prior for the reply-language and tone defaults. Treat this as a *signal*, not a confirmed preference — the Dreaming feedback loop, not this scan, is what writes confirmed comms changes. +- **Candidate goals → `profile/goals.md`:** a theme {{USER_NAME}} returns to across many sessions is a goal candidate — draft it under **Proposed (unconfirmed)** with the sessions as evidence. Never auto-confirm. diff --git a/phases/core/00-about-you.md b/phases/core/00-about-you.md new file mode 100644 index 0000000..56f0194 --- /dev/null +++ b/phases/core/00-about-you.md @@ -0,0 +1,27 @@ +--- +phase: core +name: about-you +slot: about-you +mode: [] +requires: null +--- + +## About {{USER_NAME}} — Read This First + +Before producing anything, read the user profile in `knowledge-base/profile/`: + +- **`profile/communication.md` is authoritative** for how you talk to {{USER_NAME}} — language, tone, length, notification cadence, and the escalate-vs-handle contract. It **overrides generic defaults**. Apply it to the digest, every notification, and any drafted message. If it specifies a reply language, write in that language. Never take an externally-visible action the contract says to escalate without explicit approval. +- **`profile/about-you.md`** tells you who {{USER_NAME}} is, who matters most to them, what they're currently focused on, and their working rhythm. Use it as orienting context for what to surface and how to time it. +- **`profile/goals.md`** holds confirmed goals — the prioritization lens (see the Action Items phase) — plus proposed candidates awaiting confirmation. + +*** + +### Keep the profile current (derive, don't ask) + +The profile is mostly **derived and self-maintained** — {{USER_NAME}} should rarely need to fill it in. On every run, when connector data or {{USER_NAME}}'s Claude Code sessions give you a stable signal, update the relevant `profile/` file in the same pass you update the rest of the KB: + +- **`about-you.md`** — fill/refresh role, employer/team, top collaborators (`[[people/]]`, ranked by interaction frequency and 1:1 cadence), current focus (most-active projects/threads), and working rhythm (meeting density, deep-work windows, primary channels). Tag every inferred claim `[single-source]` / `[unverified]` until a second source corroborates it; bump `last_reviewed`. +- **`goals.md`** — when activity reveals a recurring objective (a project dominating your calendar/tickets/sessions, a theme repeated across meetings), draft it under **Proposed (unconfirmed)** with the evidence behind it. **Never** move a goal to **Confirmed** yourself — confirmation is {{USER_NAME}}'s, via `/scout-profile`, a reply, or a direct edit. +- **`communication.md`** — only the Dreaming feedback loop edits this (from {{USER_NAME}}'s 👍/👎 and corrections), not a briefing run. + +**Never overwrite {{USER_NAME}}'s own edits.** Any line that is no longer a `` sentinel and isn't tagged as derived is ground truth — leave it. Replace only the TODO sentinels and your own previously-derived (still-tagged) lines. diff --git a/phases/core/action-items.md b/phases/core/action-items.md index aaa33ad..03f45de 100644 --- a/phases/core/action-items.md +++ b/phases/core/action-items.md @@ -45,6 +45,16 @@ Urgency is **capped by how far away the deadline is** — distance sets a *ceili **Evaluate the actual deadline, not the source's tone.** Notification language — "action required", "expiring soon", "final notice", "limit reached" — is alarm-word framing, not real urgency, and never promotes an item past the distance ceiling. Deprecation / end-of-life notices specifically stay 🟢 Watching until ~2–3 weeks before the cutover. This ceiling is the counterpart to the deadline *escalation* rule under Knowledge Graph Personal Tasks below: escalation raises priority as a deadline nears; the ceiling stops a distant deadline from being surfaced as urgent on tone alone. +### Goal Alignment — Secondary Signal Only + +Read the **Confirmed goals** in `knowledge-base/profile/goals.md`. Goal alignment helps {{USER_NAME}} see what advances what they're trying to achieve — but it is strictly **secondary to the urgency rules above** and must not distort them: + +- **It never changes a tier.** Goal alignment does **not** promote an item to 🔴/🟡, does **not** override the deadline-distance ceiling, and does **not** rescue noise. An item that wouldn't otherwise be surfaced stays unsurfaced no matter how on-goal it sounds. Urgency/deadline/cross-check decide the tier first; alignment only acts *after*. +- **It orders within a band.** When two items share a tier, the goal-advancing one sorts first. +- **It annotates.** When an item clearly advances a confirmed goal, append a quiet marker linking the goal: `(advances [[goals#]])`. Only for **confirmed** goals — never proposed ones. + +If `goals.md` has no confirmed goals, skip alignment entirely (no markers, no reordering). + ## Action Items File Format Create `action-items/action-items-YYYY-MM-DD.md` using today's date. Include: @@ -324,6 +334,10 @@ At the end of every briefing and consolidation run, append or update a **Scout D ### KB Growth Today - Ontology stats, new entities, patterns added + +### Goals +- **Moved today:** which confirmed `[[goals]]` today's items/activity advanced +- **Neglected:** any confirmed goal with no related activity for ~a week — one low-key line ``` **Rules:** @@ -332,3 +346,4 @@ At the end of every briefing and consolidation run, append or update a **Scout D - "Your Input Needed" lists ONLY items where {{USER_NAME}}'s action unblocks {{INSTANCE_NAME}} or a project. - Keep it scannable — no walls of text. Link to KB files for details. - On a `weekend-briefing` run, fold the **Monday Preview** into the digest rather than emitting it separately. +- **Goals lens:** populate from **confirmed** goals in `knowledge-base/profile/goals.md` only. Goal **neglect** is a low-key flag, never a 🔴 unless a goal carries a real deadline. Omit the Goals section entirely when there are no confirmed goals. Honor `profile/communication.md` cadence — don't turn this into a nag. diff --git a/phases/core/relationships.md b/phases/core/relationships.md new file mode 100644 index 0000000..f0e5a25 --- /dev/null +++ b/phases/core/relationships.md @@ -0,0 +1,33 @@ +--- +phase: core +name: relationships +slot: relationships +mode: [briefing] +requires: null +--- + +## Relationship Maintenance + +Action items track *tasks*; this tracks *relationships*. The goal is the chief-of-staff nudge {{USER_NAME}} can't get from a task list: "you haven't talked to X in a while," "this promise to a person is aging." Run this on briefing-type runs (including the weekend briefing), not on every consolidation delta. + +### Keep `last_interaction` fresh + +For each person {{USER_NAME}} interacted with this run (email, Slack, meeting, PR thread), set/update `last_interaction:` on their `knowledge-base/people/.md` entity to the most recent contact date. This is the signal everything below reads. + +### Reconnect nudges (cadence-aware, not a fixed timer) + +"Tracked" people are the ones who matter to {{USER_NAME}} — derive them the same way `about-you.md` does: top collaborators by interaction frequency and any recurring 1:1 cadence. Do **not** keep a hand-maintained list. + +For each tracked person, compare `last_interaction` against their **normal** rhythm: + +- A weekly-1:1 contact silent for a month → cooling. A monthly contact silent for a week → fine. +- Surface a cooling relationship as a **low-key digest line**, never a 🔴 (there's no deadline): "Haven't connected with [[people/]] in N weeks (usually ~weekly)." +- Skip anyone on a known leave/OOO state (check the entity, per the Action Items leave-state rule). + +### Aging promises to people + +Cross-reference open commitments {{USER_NAME}} made *to a specific person* (from the committed-reply tracking in the Slack/email phases, or KB) against `last_interaction` and elapsed time. A promise made to someone two weeks ago with no movement since is a relationship risk — surface it low-key, attributed to the person, with the original ask. + +### Respect the contract + +All relationship output obeys `profile/communication.md`. If the contract says relationship nudges are unwanted, or sets quiet hours/cadence, honor it — these are helpful prompts, not nags. Keep them in the **Scout Digest** (a brief "Relationships" note), not as separate interrupts. diff --git a/phases/modes/feedback-processing.md b/phases/modes/feedback-processing.md index c91d6fc..31d27df 100644 --- a/phases/modes/feedback-processing.md +++ b/phases/modes/feedback-processing.md @@ -83,6 +83,8 @@ Based on the classified signals and mistake audit updates, determine what change |---|---|---| | `knowledge-base/scout-mistake-audit.md` | **Direct edit** | Apply updates from Step 1c immediately | | KB files (content corrections) | **Direct edit** | Fix factual errors identified by feedback (e.g., wrong status, wrong person, outdated info) | +| `knowledge-base/profile/communication.md` | **Direct edit** | This is the channel that *learns* the comms contract. When feedback reveals a **stable** preference about how {{INSTANCE_NAME}} talks (too long/short, wrong tone, wrong language, over/under-notifying, an escalation that should've been autonomous or vice-versa), write it into the contract, cite the feedback, bump `last_reviewed`. One-off reactions aren't enough — only encode a preference that recurs or is stated outright. | +| `knowledge-base/profile/{about-you,goals}.md` | **Direct edit** | Apply {{USER_NAME}}'s corrections (wrong role/collaborator, a goal confirmed/dropped/reprioritized). Treat a confirmation as ground truth and stop tagging it derived. | | `DREAMING.md` | **Direct edit** | Improve dreaming behavior based on patterns (e.g., adjust scoring weights, add checklist items) | | `SKILL.md` | **Direct edit (transparency + reversibility)** | Self-apply additive, feedback-aligned, or pattern-closing edits directly, committed with a clear message so the change is reviewable and `git revert`-able. See gate criteria below. | | New KB files or structural changes | **Direct edit** | Only if supported by clear evidence from multiple feedback signals | diff --git a/templates/knowledge-base/ontology/schema.yaml.tmpl b/templates/knowledge-base/ontology/schema.yaml.tmpl index fd4dddf..0697038 100644 --- a/templates/knowledge-base/ontology/schema.yaml.tmpl +++ b/templates/knowledge-base/ontology/schema.yaml.tmpl @@ -6,7 +6,7 @@ entity_types: person: properties: required: [name, type] - optional: [email, slack_id, github, birthday, role, team, employer, phone] + optional: [email, slack_id, github, birthday, role, team, employer, phone, last_interaction] relationships: - works_with - manages diff --git a/templates/knowledge-base/profile/about-you.md.tmpl b/templates/knowledge-base/profile/about-you.md.tmpl new file mode 100644 index 0000000..155ffc2 --- /dev/null +++ b/templates/knowledge-base/profile/about-you.md.tmpl @@ -0,0 +1,34 @@ +--- +kind: profile +last_reviewed: {{TODAY_DATE}} +--- + +# About {{USER_NAME}} + +> **{{INSTANCE_NAME}} maintains this file.** Most of it is *derived* from your activity (connectors + your Claude Code sessions) and kept fresh automatically. Edit any line directly — {{INSTANCE_NAME}} treats your edits as ground truth and will not overwrite them. Lines {{INSTANCE_NAME}} inferred carry a confidence tag (`[single-source]` / `[unverified]`) until corroborated. + +## Identity + +- **Name:** {{USER_NAME}} +- **Email:** {{USER_EMAIL}} +- **Timezone:** {{TIMEZONE}} +- **Role / title:** +- **Employer / team:** + +## Who matters most + +_Top collaborators, derived from interaction frequency and 1:1 cadence. Wikilink to `[[people/]]`. {{INSTANCE_NAME}} keeps this current; correct it freely._ + + + +## Current focus + +_What you're actively spending time on (most-active projects/tickets/threads). {{INSTANCE_NAME}} derives this; it feeds prioritization alongside `[[goals]]`._ + + + +## Working rhythm + +_Meeting density, deep-work windows, and primary channels — derived from calendar and tool traffic. Used to time nudges and respect your focus blocks._ + + diff --git a/templates/knowledge-base/profile/communication.md.tmpl b/templates/knowledge-base/profile/communication.md.tmpl new file mode 100644 index 0000000..9aad7cd --- /dev/null +++ b/templates/knowledge-base/profile/communication.md.tmpl @@ -0,0 +1,35 @@ +--- +kind: profile +last_reviewed: {{TODAY_DATE}} +--- + +# How {{INSTANCE_NAME}} talks to {{USER_NAME}} + +> **This file is authoritative for every {{INSTANCE_NAME}} output** — the digest, notifications, and any drafted message. It governs language, tone, length, cadence, and what gets escalated vs. handled. Defaults below are a starting point; {{INSTANCE_NAME}} refines them automatically from your feedback (👍/👎, corrections), and you can edit them anytime or via `/scout-profile`. + +## Language + +- **Reply in:** English (until inferred otherwise) + +## Tone & length + +- **Tone:** balanced and direct (default) +- **Length:** scannable bullets, lead with what needs action (default) +- Lead with the conclusion. No filler, no flattery. Flag uncertainty rather than hiding it. + +## Notification cadence + +- Respect the schedule: the morning briefing + scheduled consolidations carry the load. Don't manufacture interrupts. +- Relationship nudges and goal-neglect flags go in the digest **low-key** — never as a 🔴 unless there's a real deadline. +- + +## Escalate vs. handle (autonomy contract) + +{{INSTANCE_NAME}} never takes an externally-visible action (send, merge, schedule, reply) without explicit approval — that stays true regardless of the settings below. + +- **Always check with {{USER_NAME}} first:** +- **Safe to handle and just report:** + +## Don't + +- diff --git a/templates/knowledge-base/profile/goals.md.tmpl b/templates/knowledge-base/profile/goals.md.tmpl new file mode 100644 index 0000000..a869cfe --- /dev/null +++ b/templates/knowledge-base/profile/goals.md.tmpl @@ -0,0 +1,20 @@ +--- +kind: profile +last_reviewed: {{TODAY_DATE}} +--- + +# Goals — {{USER_NAME}} + +> **Goals are the lens {{INSTANCE_NAME}} prioritizes through:** within each urgency band, items that advance a confirmed goal surface first, and a goal that gets no attention for a while is flagged. You don't fill this in by hand — {{INSTANCE_NAME}} **proposes** candidate goals from your activity (most-active projects, recurring themes in meetings and your Claude Code sessions) and you **confirm or edit** them. Confirmed goals drive prioritization; proposed ones don't until you accept them. + +## Confirmed goals + +_Format: `### ` + a one-line **Why** + horizon (e.g. Q3 2026). Reference related work with `[[wikilinks]]`. Confirmed via `/scout-profile`, a reply, or by editing this file directly — {{INSTANCE_NAME}} never auto-confirms._ + + + +## Proposed (unconfirmed) + +_{{INSTANCE_NAME}} drafts candidate goals here from observed activity, each with the evidence it's based on. Move one up to **Confirmed** to make it a prioritization driver, or delete it._ + +