원클릭으로
learn
Turn reusable findings into scoped policies or insight files.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Turn reusable findings into scoped policies or insight files.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Deploy or share generated HQ artifacts through hq-deploy.
Mark a company as HQ Pro cloud-backed and sync its team setup.
Send HQ Sync direct messages, prompts, details, or scheduled notes to teammates.
Run a full bidirectional sync for cloud-backed HQ companies.
Scaffold a new HQ company AND optionally take it all the way to operational — business-discovery interview, seeded knowledge/workers/skills/projects, brand design packs (generated from website/PDF/Drive and bound to deploys via policy), connected integrations, org groups + ACL rules, teammate invites, and optional cloud agents.
Resolve HQ Sync conflicts by choosing local, cloud, or discard.
| name | learn |
| description | Turn reusable findings into scoped policies or insight files. |
| allowed-tools | Read, Write, Edit, Grep, Glob, Bash(qmd:*), Bash(grep:*), Bash(mkdir:*), Bash(date:*), Bash(ls:*), Bash(bash:*), Bash(git:*), Bash(rm:*), Bash(stat:*), Bash |
Capture a learning, classify it, and inject the rule directly into the file it governs (or the insight into the insight tree).
Called programmatically by /execute-task and /run-project after task completion or failure. Also callable manually with --hard flag for hard-enforcement rules (formerly /learn --hard). /handoff and /checkpoint call this for session insights.
Input: the user's argument — structured JSON event data, free text description, or empty/"auto" for hook-triggered mode.
Two output types, one pipeline. Content is classified (Step 1.5) and routed to the appropriate format:
| Scope | Target directory | Format |
|---|---|---|
| Company | companies/{co}/policies/{slug}.md | Policy file (YAML frontmatter + Rule + Rationale) |
| Repo | repos/{pub|priv}/{repo}/.claude/policies/{slug}.md | Policy file |
| Command (operator) | personal/policies/{slug}.md (scope: command) | Policy file |
| Global / personal (default) | personal/policies/{slug}.md (scope: global) | Policy file |
| Worker (legacy) | core/workers/*/{id}/worker.yaml | Instructions block ## Learnings |
/learnnever writes tocore/policies/.core/is release-shipped scaffold, replaced wholesale by/update-hq— anything written there is lost on the next upgrade (hard policyhq-customizations-live-in-personal-or-company). Operator-universal learnings go topersonal/policies/, whichreindex.shsymlinks back intocore/policies/so they still load as global at SessionStart — but live in an upgrade-safe location. A genuine product-level core policy (one that should ship to every HQ install) is not captured via/learn: author it locally, then publish through the hq-core staging repo +/promote-hq-core(seestaging-promotion-required). If a learning is judged truly core,/learnstops and points you at that pipeline rather than writing intocore/.
| Scope | Target directory | Format |
|---|---|---|
| Global / repo | workspace/insights/global/{slug}.md | Insight file (YAML frontmatter + Insight + Context) |
| Company | companies/{co}/knowledge/insights/{slug}.md | Insight file (inside company knowledge repo) |
| Tool | workspace/insights/tools/{slug}.md | Insight file |
| Conceptual | workspace/insights/concepts/{slug}.md | Insight file |
See core/knowledge/public/hq-core/insights-spec.md for the insight file format.
Before creating: always scan existing policies/insights for updates (Step 4.5). Update > duplicate.
Before processing, load applicable policies with minimal context burn:
core/policies/ (skip example-policy.md), run bash core/scripts/read-policy-frontmatter.sh {file} to get frontmatter-onlyenforcement: hard titles. Only Read the ## Rule section of hard-enforcement policies if one looks relevant to the current learningSkip full policy body loads — the frontmatter contains enough metadata for the learn pipeline.
Three input modes:
If the argument is empty or "auto":
workspace/learnings/.observe-patterns-latest.jsonobservations arraypattern_type, confidence, description, severity, evidencesource: "hook-observation", scope: "global" (or inferred from pattern type)Example .observe-patterns-latest.json:
{
"metadata": {
"created_at": "2026-03-07T21:35:00Z",
"session_end_timestamp": "20260307-213500",
"git_branch": "main",
"git_commit": "abc1234",
"project_context": "hq"
},
"observations": [
{
"pattern_type": "back-pressure-retry",
"confidence": 0.8,
"description": "Git log shows fixup/amend commits",
"severity": "high",
"evidence": "fixup commits in recent history",
"recommendation": "Extract pattern about what caused retry"
}
]
}
Note: in Codex runtime, the observe-patterns hook is not wired up, so this mode typically returns empty — fall through to manual modes.
If input is a JSON object:
{
"task_id": "TASK-001",
"project": "my-project",
"source": "back-pressure-failure|user-correction|success-pattern|task-completion|build-activity|hook-observation|session-insight",
"severity": "critical|high|medium|low",
"scope": "global|worker:{id}|command:{name}|knowledge:{path}|project:{slug}",
"workers_used": ["backend-dev"],
"back_pressure_failures": [{"worker": "frontend-dev", "check": "lint", "error": "..."}],
"retries": 0,
"key_decisions": ["..."],
"issues_encountered": ["..."],
"patterns_discovered": ["..."]
}
Parse it and proceed to Step 1.5.
Parse for keywords to determine scope. Generate rule statement from the description. Proceed to Step 1.5.
If the input starts with [ (JSON array), enter batch mode:
Batch input format:
[
{"type": "rule|insight", "content": "...", "scope": "global|company:{co}|...", "source": "..."},
...
]
Batch processing rules:
[), enter batch modecontent fields as a single query string for a single qmd vsearch call, then match results against each item individuallyDetermine if input is an operational rule or an educational insight:
| Signal | Type | Route to |
|---|---|---|
| NEVER/ALWAYS/condition→action | rule | Policy file (Steps 2–6) |
| "why X works", "pattern behind", conceptual explanation | insight | workspace/insights/ or companies/{co}/knowledge/insights/ (Step 5b) |
User correction (/learn --hard) | rule | Policy file (always) |
back_pressure_failures | rule | Policy file (always) |
patterns_discovered (educational) | insight | Insight file (Step 5b) |
source: "session-insight" | insight | Insight file (always — from /handoff or /checkpoint step 0c) |
Default: if ambiguous, route as policy (existing behavior). Insights are opt-in.
If content type is insight, skip Steps 2 and 5 (rule extraction and policy creation). Proceed to Step 3 for scope classification, Step 4 for dedup, then Step 5b for insight file creation.
From structured input, generate rules:
back_pressure_failures → NEVER: {anti-pattern that caused failure} (scope: worker:{id})retries > 0 → Rule about what caused retry and how to avoid itkey_decisions → ALWAYS: {pattern} if broadly applicableissues_encountered → Scoped rule to prevent recurrencepatterns_discovered → ALWAYS: {pattern} for success patternsFrom free text:
If no meaningful rules can be extracted (task completed cleanly, no failures, no notable patterns), skip injection — log to event log only.
For each extracted rule, determine scope (most specific wins):
| Signal | Scope | Policy directory |
|---|---|---|
| Related to specific company | company | companies/{co}/policies/ |
| Related to specific repo | repo | repos/{pub|priv}/{repo}/.claude/policies/ |
| Error in specific command | command | personal/policies/ (with scope: command) |
| Failure in specific worker | worker | core/workers/*/{id}/worker.yaml instructions block (legacy, still supported) |
| Active session company (when no explicit repo, command, or global scope) | company | companies/{co}/policies/ |
| Universal pattern (default when no company/repo/session context) | global | personal/policies/ |
| User correction via /learn --hard | From context; default to active session company, then global | Detected scope directory |
/learn does not target core/policies/. The global/command rows route to personal/policies/ — operator-owned and upgrade-safe — and reindex.sh symlinks each entry into core/policies/ so it still loads as a global/command policy. Reserve core/policies/ for release-shipped policies authored through the staging → /promote-hq-core pipeline. If a rule is genuinely product-core (must ship to every HQ install), stop and direct the user to that pipeline; never Write it into core/.
Primary output = policy files. The canonical format for persistent rules is structured policy files (per core/knowledge/public/hq-core/policies-spec.md). Worker.yaml injection is still supported for worker-specific learnings.
Resolve company/repo context (strongest signal wins):
repo, command, or global scope rather than the session default; explicit global scope targets personal/policies/. Verify an explicit company slug against the manifest.companies/<slug>/ segment (the last one in the path, not the first)prd.json metadata if in project contextcompanies/manifest.yaml repo lookup if in repo contextcompanies/{co}/workers/ → {co})bash core/scripts/hq-session.sh get company_slug. For free-text and /learn --hard input with no explicit repo, command, or global scope, default to this active company and target companies/{co}/policies/.Verify every resolved slug, including the active session company_slug, exists in companies/manifest.yaml before targeting companies/{co}/policies/. If the session value is absent or invalid, do not treat it as company context.
Never silently fall back to a global target for a company-specific learning. A global target (→ personal/policies/) is correct ONLY when the rule is genuinely universal to this operator's HQ. If a rule is clearly company-specific but the company can't be resolved unambiguously, stop and ask which company — do not default the write into personal/policies/ (and never into core/policies/). A misrouted company policy syncs into the wrong tenant vault on the next hq-sync (HQ-Pro), a category-1 cross-company bug. See core/policies/hq-company-scoped-writes-verify-company.md.
Primary (if qmd available):
qmd vsearch "{rule text}" --json -n 5
Check results for similarity to the new rule:
Fallback (if qmd unavailable): Use Grep to search for key terms from the rule across the policy directories:
*.md in companies/*/policies/, personal/policies/, core/policies/ (the symlinked + shipped set), and any repo policy dirsReport dedup action taken.
Before creating a new rule, check if an existing policy file already covers this topic:
Resolve policy directories based on scope:
companies/{co}/policies/ (skip example-policy.md){repoPath}/.claude/policies/personal/policies/ (the write target) and core/policies/ (catches shipped + already-symlinked rules)Search for matching policies:
# Grep policy titles and rules for keyword overlap
grep -rl "{key terms from rule}" {policy_dir}/*.md 2>/dev/null
Also check qmd vsearch results from Step 4 for hits in policy files.
If matching policy found:
## Rule section, bump version, update updated datededup_action: "merged-into-policy" in event logIf no matching policy found:
core/knowledge/public/hq-core/policies-spec.md) over injecting into worker.yaml. Policy files are the canonical format for persistent rules. Never write a learned rule into .claude/CLAUDE.md / AGENTS.md — the charter is release-shipped scaffold, not a learning store (policy learned-rules-never-in-claude-md)If Step 4.5 found a matching policy → update was already handled. Otherwise, create a new policy file.
Target directory:
companies/{co}/policies/{slug}.mdrepos/{pub|priv}/{repo}/.claude/policies/{slug}.mdpersonal/policies/{slug}.md (scope: command)personal/policies/{slug}.md (scope: global) — default for non-company/non-repo rulesNever Write a
.mdintocore/policies/from/learn— it is lost on/update-hqand is now mechanically blocked byprotect-core.sh(the block message points back here).personal/policies/entries are symlinked intocore/policies/byreindex.sh, so they load identically as global/command policies. Genuine product-core policies ship via the staging →/promote-hq-corepipeline only.
Create the directory if needed:
mkdir -p {target_directory}
Policy file format (per core/knowledge/public/hq-core/policies-spec.md):
---
id: {scope-prefix}-{slug}
title: {Rule title}
scope: {company|repo|command|global}
trigger: {when this applies}
when: {boolean trigger expr over context words, or `always`}
on: {[PreToolUse, PostToolUse, UserPromptSubmit, AssistantIntent] | [SessionStart]}
enforcement: {hard|soft}
public: {true|false}
version: 1
created: {YYYY-MM-DD}
updated: {YYYY-MM-DD}
source: {back-pressure-failure|user-correction|success-pattern|task-completion|hook-observation}
# applies_to: [vercel, clerk] # optional — stack-specific filter; see mapping below
---
## Rule
{Rule in imperative form}
## Rationale
{Why this rule exists — from context/failure/correction}
Enforcement mapping:
source: user-correction → enforcement: hardseverity: critical → enforcement: hardenforcement: softwhen: / on: trigger (just-in-time injection):
when: is a boolean expression over an OPEN token set — any word that appears in the relevant command/prompt/AI-message text is a live token (git && push, refactor, supabase, .tsx, /deep-plan, secret || credential). Pick the word(s) that naturally show up when the rule is relevant. Operators: && || ! ( ). Full grammar + fact derivation: core/knowledge/public/hq-core/policies-spec.md.on: is where it is evaluated. Default for a real trigger: [PreToolUse, PostToolUse, UserPromptSubmit, AssistantIntent] (the when: does the filtering). Use [SessionStart] only with when: always for ambient governance rules with no concrete signal.when: always + on: [SessionStart] — but prefer a real trigger so the rule loads just-in-time, not every session.migrate-policy-triggers.sh hook backfills them from tags: + trigger: on the next session. Setting them at authoring time is better — the migrator never overwrites an existing when:.applies_to: field mapping (stack applicability filter):
applies_to: line ONLY when the rule is wrong or useless without a specific service. Tag vocabulary must match the services: enum used in companies/manifest.yaml plus inferred vercel / aws. Examples:
applies_to: [vercel]applies_to: [clerk, vercel][clerk, vercel] means "load if workspace has clerk OR vercel." Omit the field for the 89%+ cross-cutting case.bash core/scripts/validate-policy-tags.sh after write (it fails on unknown tags — prevents typos that would silently filter everywhere).core/knowledge/public/hq-core/policies-spec.md → "Applicability Tagging (applies_to)" section.Slug generation: lowercase, hyphens, from rule keywords. Prefix: {co}- for company, {repo}- for repo, hq-cmd-{name}- for command, hq- for global.
For worker-specific learnings, still inject into core/workers/*/{id}/worker.yaml instructions block:
instructions: |
...existing instructions...
## Learnings
- NEVER: {new rule}
If Step 1.5 classified content as insight, skip Step 5 (policy creation) and create an insight file instead.
Target directory by scope:
workspace/insights/global/{slug}.mdcompanies/{co}/knowledge/insights/{slug}.md (create insights/ subdir if needed)workspace/insights/tools/{slug}.mdworkspace/insights/concepts/{slug}.mdInsight file format (per core/knowledge/public/hq-core/insights-spec.md):
---
type: insight
domain: [engineering]
tags: [topic-tags]
scope: global | company:{co} | repo:{repo} | tool:{tool}
source_session: T-{timestamp}-{slug}
created: {YYYY-MM-DD}
confidence: high | medium
relates_to: []
---
# {Title}
## Insight
{Core conceptual understanding, 2-4 paragraphs. Educational, not directive.}
## Context
{When/why this matters. What situation makes this knowledge valuable.}
## Example
{Optional. Concrete example showing the insight in practice.}
Slug generation: kebab-case from title keywords, max 60 chars. No scope prefix (subdirectory provides scope).
Confidence mapping:
confidence: highconfidence: mediumAfter writing: proceed to Step 7 (event logging).
Global promotion means raising a rule's enforcement to hard, in a policy file — never injecting it into the charter. Learned rules never go in .claude/CLAUDE.md / AGENTS.md (policy learned-rules-never-in-claude-md); they already surface for every session through the policy trigger hook (inject-policy-on-trigger.sh), so a hard-enforcement policy file is the global path.
If a rule meets ANY of:
severity == criticalsource == user-correction (explicit /learn --hard invocation)then ensure it lives as a hard-enforcement policy file at global scope:
personal/policies/{slug}.md (reindex symlinks it into core/policies/, so it rides global scope and survives /update-hq).core/policies/{slug}.md with the public marker (promoted via hq-pack-admin).Set enforcement: hard in the policy frontmatter and ensure the file carries when:/on: frontmatter so the SessionStart trigger hook surfaces it (Step 8). Do not touch CLAUDE.md.
mkdir -p workspace/learnings
Write workspace/learnings/learn-{YYYYMMDD-HHMMSS}.json:
{
"event_id": "learn-{timestamp}",
"content_type": "rule|insight",
"rules": [
{
"rule": "NEVER: ...",
"scope": "worker:frontend-dev",
"target_file": "core/workers/public/dev-team/frontend-dev/worker.yaml",
"severity": "high"
}
],
"source": "back-pressure-failure|session-insight",
"task_id": "TASK-001",
"project": "my-project",
"dedup_action": "new|merged|skipped",
"promoted_to_global": true,
"created_at": "{ISO8601}"
}
The event log write is mandatory for every invocation (even skipped/trivial ones) — downstream tooling relies on it.
qmd update 2>/dev/null || true
No manual digest rebuild is needed: policies surface automatically via the SessionStart trigger hook (inject-policy-on-trigger.sh) and the migrate-policy-triggers.sh backfill. Ensure any new policy file carries when:/on: frontmatter so it gets injected. (Personal entries are symlinked into core/policies/ by reindex.sh — run reindex or wait for its Stop/PostToolUse trigger if the symlink isn't present yet.)
Insight-only runs (content_type: insight) write no policy file, so there is nothing for the trigger hook to surface.
Batch mode note: In batch mode (Mode 4), there is no per-item or end-of-batch digest step — each policy file written during the batch surfaces on its own via its when:/on: frontmatter.
For rules (content_type: rule):
Learning captured:
Scope: {company:<slug> | repo:<name> | command | global}
Rule: {rule}
Target: {policy file path | worker.yaml path}
Action: {created-policy | updated-policy | merged-into-policy | worker-yaml-injection}
Global: {promoted|not promoted}
Dedup: {new|merged|skipped}
Event: workspace/learnings/learn-{timestamp}.json
For any scope: company rule, surface the resolved company slug and the full target path and confirm them before writing — this is the visible checkpoint that catches a misroute before it reaches a tenant vault (hq-company-scoped-writes-verify-company).
For insights (content_type: insight):
Insight captured:
Title: {insight title}
Target: {insight file path}
Action: {created-insight | updated-insight | merged-into-insight}
Dedup: {new|merged|skipped}
Event: workspace/learnings/learn-{timestamp}.json
If multiple rules/insights were extracted, report each.
.claude/CLAUDE.md / AGENTS.md; global promotion = a hard-enforcement policy file (policy learned-rules-never-in-claude-md)when:/on: frontmatter — that is what the SessionStart trigger hook (inject-policy-on-trigger.sh) uses to surface a policy; no manual digest rebuild exists anymoreworkspace/learnings/learn-{timestamp}.json is non-optional