diff --git a/.sf/ANTI-GOALS.md b/.sf/NON-GOALS.md similarity index 98% rename from .sf/ANTI-GOALS.md rename to .sf/NON-GOALS.md index bb52f8173..c161dc129 100644 --- a/.sf/ANTI-GOALS.md +++ b/.sf/NON-GOALS.md @@ -1,4 +1,4 @@ -# Anti-goals +# Non-goals - SF must not ship or revive an MCP server package or runtime endpoint. SF may consume external MCP servers as a client, but its own tools remain native SF/pi tools. - Runtime state files under `.sf/` must not become a peer source of truth when SQLite can hold the structured state. JSON, JSONL, and Markdown runtime artifacts are generated evidence, projections, or legacy import inputs. diff --git a/.sf/TASTE.md b/.sf/STYLE.md similarity index 99% rename from .sf/TASTE.md rename to .sf/STYLE.md index a97fb91ba..1e4fb06e2 100644 --- a/.sf/TASTE.md +++ b/.sf/STYLE.md @@ -1,4 +1,4 @@ -# Taste +# Style - Prefer runtime adapters over ad hoc file parsing when reading SF state. For example, query solver eval history through `sf-db.js` helpers rather than reading `.sf/evals/**/report.json`. - Make DB-backed tools the pleasant path. If a human-readable file mirrors structured state, prefer a tool that mutates the DB and regenerates the file over hand-editing the projection. diff --git a/src/resources/extensions/sf/auto-bootstrap-context.js b/src/resources/extensions/sf/auto-bootstrap-context.js index cdfc989cb..6ff087baf 100644 --- a/src/resources/extensions/sf/auto-bootstrap-context.js +++ b/src/resources/extensions/sf/auto-bootstrap-context.js @@ -21,9 +21,9 @@ const AUTO_BOOTSTRAP_SF_SPEC_FILES = [ ".sf/RUNTIME.md", ".sf/STATE.md", ".sf/PRINCIPLES.md", - ".sf/TASTE.md", + ".sf/STYLE.md", ".sf/preferences.yaml", - ".sf/ANTI-GOALS.md", + ".sf/NON-GOALS.md", ".sf/CODEBASE.md", ]; const AUTO_BOOTSTRAP_ORIENTATION_FILES = [ @@ -117,7 +117,7 @@ export function buildAutoBootstrapContext(basePath) { "Use explorer-style subagents or equivalent high-context research passes before planning when the runtime supports them.", "Recommended explorer passes: docs/purpose/vision; source architecture and dependency map; tests/gates/tooling; risks/backlog/eval candidates.", "Merge explorer findings into one repo map with cited file paths before creating milestones.", - "Follow harness-engineering principles: keep AGENTS.md short as a table of contents, use docs/ for human exports and git-history reports, capture operational knowledge in .sf/DB-backed state, prefer mechanically enforced architecture/taste rules, and add cleanup/gardening work when repo knowledge is stale.", + "Follow harness-engineering principles: keep AGENTS.md short as a table of contents, use docs/ for human exports and git-history reports, capture operational knowledge in .sf/DB-backed state, prefer mechanically enforced architecture/style rules, and add cleanup/gardening work when repo knowledge is stale.", "Optimize for agent legibility: every milestone should improve the next agent's ability to understand, validate, and safely modify the repo.", "Create actionable milestones and slices from the repo's docs and source tree rather than asking the user to restate them.", "", diff --git a/src/resources/extensions/sf/bootstrap/system-context.js b/src/resources/extensions/sf/bootstrap/system-context.js index 125dea257..b173ffd4a 100644 --- a/src/resources/extensions/sf/bootstrap/system-context.js +++ b/src/resources/extensions/sf/bootstrap/system-context.js @@ -446,7 +446,7 @@ function loadSelfFeedbackBlock(cwd) { return `\n\n[SELF-FEEDBACK — Recent sf-internal anomalies]\n\n${block}`; } /** - * Load tacit knowledge files (.sf/PRINCIPLES.md, .sf/TASTE.md, .sf/ANTI-GOALS.md) + * Load tacit knowledge files (.sf/PRINCIPLES.md, .sf/STYLE.md, .sf/NON-GOALS.md) * into a single block injected after the architecture block. * * Each section is capped at 4 KB. Sections are skipped silently when the @@ -475,13 +475,13 @@ export function loadTacitKnowledgeBlock(cwd) { return stripped; } const principles = readSection("PRINCIPLES.md"); - const taste = readSection("TASTE.md"); - const antiGoals = readSection("ANTI-GOALS.md"); - if (!principles && !taste && !antiGoals) return ""; + const style = readSection("STYLE.md"); + const nonGoals = readSection("NON-GOALS.md"); + if (!principles && !style && !nonGoals) return ""; const parts = ["[TACIT KNOWLEDGE — read carefully]"]; if (principles) parts.push(`\n## Principles\n\n${principles}`); - if (taste) parts.push(`\n## Taste\n\n${taste}`); - if (antiGoals) parts.push(`\n## Anti-goals\n\n${antiGoals}`); + if (style) parts.push(`\n## Style\n\n${style}`); + if (nonGoals) parts.push(`\n## Non-goals\n\n${nonGoals}`); return `\n\n${parts.join("\n")}`; } /** diff --git a/src/resources/extensions/sf/gitignore.js b/src/resources/extensions/sf/gitignore.js index 183b92996..aa03c8045 100644 --- a/src/resources/extensions/sf/gitignore.js +++ b/src/resources/extensions/sf/gitignore.js @@ -20,7 +20,7 @@ export { SF_RUNTIME_PATTERNS } from "./git-runtime-patterns.js"; /** * SF runtime/generated exclusion patterns for repos where .sf/ is a LOCAL DIRECTORY. * Granular so deliberate human-authored guidance such as .sf/PRINCIPLES.md, - * .sf/TASTE.md, and .sf/ANTI-GOALS.md can remain trackable. + * .sf/STYLE.md, and .sf/NON-GOALS.md can remain trackable. * * NOT used when .sf/ is a symlink — symlinks need the blanket SF_SYMLINK_EXCLUSION_PATTERNS * because git cannot traverse symlinks to match per-file patterns. diff --git a/src/resources/extensions/sf/milestone-framing-check.js b/src/resources/extensions/sf/milestone-framing-check.js index 00a603055..586d6da0d 100644 --- a/src/resources/extensions/sf/milestone-framing-check.js +++ b/src/resources/extensions/sf/milestone-framing-check.js @@ -3,7 +3,7 @@ * * Reviews: * 1. Milestone CONTEXT.md / title against PROJECT.md vision - * 2. .sf/ANTI-GOALS.md — does this milestone violate any? + * 2. .sf/NON-GOALS.md — does this milestone violate any? * 3. Category error: is this solving the right problem? * * Non-blocking: findings are surfaced as structured annotations. @@ -13,11 +13,11 @@ import { existsSync, readdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { sfRoot } from "./paths.js"; /** - * Check milestone framing against project vision, anti-goals, and category-error heuristics. + * Check milestone framing against project vision, non-goals, and category-error heuristics. * * Reads: * - /PROJECT.md (vision) - * - /.sf/ANTI-GOALS.md + * - /.sf/NON-GOALS.md * - /.sf/milestones//-CONTEXT.md (or CONTEXT.md) * * @param basePath - project root (cwd) @@ -30,8 +30,8 @@ export function checkMilestoneFraming(basePath, milestoneId) { const projectMdPath = join(basePath, "PROJECT.md"); const projectMd = safeRead(projectMdPath); const sfDir = sfRoot(basePath); - const antiGoalsPath = join(sfDir, "ANTI-GOALS.md"); - const antiGoalsMd = safeRead(antiGoalsPath); + const nonGoalsPath = join(sfDir, "NON-GOALS.md"); + const nonGoalsMd = safeRead(nonGoalsPath); // Try to find milestone context file const milestonePath = join(sfDir, "milestones", milestoneId); const contextCandidates = [ @@ -49,14 +49,14 @@ export function checkMilestoneFraming(basePath, milestoneId) { if (!contextMd) return findings; // nothing to check const contextLower = contextMd.toLowerCase(); // ── Anti-goal keyword check ────────────────────────────────────────────── - if (antiGoalsMd) { - const antiGoalLines = extractBulletLines(antiGoalsMd); - for (const line of antiGoalLines) { + if (nonGoalsMd) { + const nonGoalLines = extractBulletLines(nonGoalsMd); + for (const line of nonGoalLines) { const keywords = extractKeywords(line); const matched = keywords.filter((kw) => contextLower.includes(kw)); if (matched.length > 0) { findings.push({ - concern: `Milestone description contains "${matched[0]}" — ANTI-GOALS.md entry: "${line.slice(0, 120)}"`, + concern: `Milestone description contains "${matched[0]}" — NON-GOALS.md entry: "${line.slice(0, 120)}"`, source: "anti_goal", severity: "warning", }); @@ -144,7 +144,7 @@ function extractBulletLines(text) { } /** * Extract significant lowercase keywords (length >= 5, non-common) from text. - * Used for fuzzy matching between milestone context and anti-goals / vision. + * Used for fuzzy matching between milestone context and non-goals / vision. */ function extractKeywords(text) { const stopwords = new Set([ diff --git a/src/resources/extensions/sf/scaffold-constants.js b/src/resources/extensions/sf/scaffold-constants.js index a959beaae..1659ff7fe 100644 --- a/src/resources/extensions/sf/scaffold-constants.js +++ b/src/resources/extensions/sf/scaffold-constants.js @@ -434,8 +434,8 @@ Add entries as you make decisions. Each entry: 1-2 sentences. Cite the rationale `, }, { - path: ".sf/TASTE.md", - content: `# Taste + path: ".sf/STYLE.md", + content: `# Style What good code looks like here. Idioms, conventions, "we prefer X over Y" calls. @@ -447,10 +447,10 @@ Add entries as you notice patterns worth preserving. Each entry: 1-2 sentences w `, }, { - path: ".sf/ANTI-GOALS.md", - content: `# Anti-goals + path: ".sf/NON-GOALS.md", + content: `# Non-goals -What we explicitly DON'T want. Things that look attractive but we've decided against. +What this project explicitly does not want. Things that look attractive but have been decided against. This is gold — most wrong agent calls come from not knowing what to avoid. Each entry: 1-2 sentences with the rationale. diff --git a/src/resources/extensions/sf/spec-projections.js b/src/resources/extensions/sf/spec-projections.js index b71935280..c0e79715d 100644 --- a/src/resources/extensions/sf/spec-projections.js +++ b/src/resources/extensions/sf/spec-projections.js @@ -75,8 +75,8 @@ export function buildWorkingModelInputs(basePath) { `- Generator: \`sf-spec-projections@${SPEC_GENERATOR_VERSION}\``, `- Database: \`.sf/sf.db\` (${present(join(sfDir, "sf.db"))})`, `- Guidance: \`.sf/PRINCIPLES.md\` (${present(join(sfDir, "PRINCIPLES.md"))})`, - `- Guidance: \`.sf/TASTE.md\` (${present(join(sfDir, "TASTE.md"))})`, - `- Guidance: \`.sf/ANTI-GOALS.md\` (${present(join(sfDir, "ANTI-GOALS.md"))})`, + `- Guidance: \`.sf/STYLE.md\` (${present(join(sfDir, "STYLE.md"))})`, + `- Guidance: \`.sf/NON-GOALS.md\` (${present(join(sfDir, "NON-GOALS.md"))})`, `- Optional knowledge: \`.sf/KNOWLEDGE.md\` (${present(join(sfDir, "KNOWLEDGE.md"))})`, `- Optional preferences: \`.sf/preferences.yaml\` (${present(join(sfDir, "preferences.yaml"))})`, readDbSummary(basePath), @@ -193,7 +193,7 @@ export function generateOperatingModelSpec(basePath) { "", "Markdown under `.sf/` has two roles:", "", - "- working guidance and knowledge that the runtime loads, such as `PRINCIPLES.md`, `TASTE.md`, `ANTI-GOALS.md`, `KNOWLEDGE.md`, and `preferences.yaml`;", + "- working guidance and knowledge that the runtime loads, such as `PRINCIPLES.md`, `STYLE.md`, `NON-GOALS.md`, `KNOWLEDGE.md`, and `preferences.yaml`;", "- human-readable projections from DB-owned records, such as rendered decisions, requirements, roadmap, plan, summary, and state files.", "", "Markdown under `docs/specs/` is a human export for review, navigation, and git history. Generated docs can change; Git records that human-facing history. If SF needs its own operational history, it should store that in `.sf`/DB-backed state. Plans should record any surface, protocol, output-format, run-control, or permission-profile impact explicitly when a milestone changes integration behavior.", @@ -234,7 +234,7 @@ export function generateOperatingModelSpec(basePath) { "", "- `.sf/sf.db` is the canonical structured runtime state store for initialized SF repos. Treat a missing or unreadable DB as bootstrap/recovery, not a normal alternate source of truth.", "- `.sf/DECISIONS.md`, `.sf/REQUIREMENTS.md`, milestone roadmaps, and similar files are rendered working projections when database-backed tools own the data. They are useful to humans and agents but must not compete with DB rows.", - "- `.sf/PRINCIPLES.md`, `.sf/TASTE.md`, `.sf/ANTI-GOALS.md`, `.sf/KNOWLEDGE.md`, and `.sf/preferences.yaml` are repo-local working guidance files when present.", + "- `.sf/PRINCIPLES.md`, `.sf/STYLE.md`, `.sf/NON-GOALS.md`, `.sf/KNOWLEDGE.md`, and `.sf/preferences.yaml` are repo-local working guidance files when present.", "- Generated `.sf/` runtime files are evidence, projections, or import/recovery artifacts.", "- Durable human-facing exports belong in `docs/specs/`, `docs/adr/`, or `docs/plans/`. They are reviewable projections and git-history artifacts, not a second planning database.", "",