Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"upstream/skills/",
"agents/",
"commands/",
"principles/",
"docs/agents/"
],
"scripts": {
Expand Down
41 changes: 41 additions & 0 deletions principles/karpathy-primary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Andrej Karpathy's Coding Principles

## Principle 1: Think Before Coding

Before writing a single line of code, think through the problem thoroughly. Understand the requirements, design the approach, and consider edge cases. Most coding time should be spent thinking, not typing. A clear mental model prevents rework and produces cleaner solutions.

Ask yourself:
- What exactly am I trying to accomplish?
- What are the constraints and edge cases?
- What is the simplest approach that could work?
- How will I verify correctness?

## Principle 2: Simplicity First

Always reach for the simplest solution first. Simple code is easier to understand, debug, test, and extend. Resist the urge to build elaborate abstractions or optimize prematurely. Complexity should be earned — only introduce it when the simple solution demonstrably falls short.

Guidelines:
- Write code a junior engineer can understand
- Avoid premature abstraction and optimization
- Delete code whenever possible — less code is better code
- Favor boring, proven patterns over clever, novel ones

## Principle 3: Surgical Changes

Make the smallest possible change to achieve the goal. Each change should do exactly one thing, and do it well. Do not refactor unrelated code, fix unrelated bugs, or add "while I'm here" improvements. Precise, minimal changes reduce risk and make review straightforward.

Guidelines:
- One logical change per commit/PR
- Don't mix refactoring with feature work
- Leave the codebase cleaner than you found it — but only in the area you're touching
- If you see something broken that's out of scope, file an issue, don't fix it inline

## Principle 4: Goal-Driven Execution

Stay relentlessly focused on the goal. Do not chase shiny objects, explore interesting tangents, or get sidetracked by adjacent improvements. Every action should trace back to the acceptance criteria. If it's not required to meet the goal, it's a distraction.

Guidelines:
- Before every action, ask: "Does this directly advance the goal?"
- Track progress against acceptance criteria, not against interesting side quests
- Timebox exploration — if you need to research, set a limit and return to the goal
- Ship the minimum viable implementation, then iterate
61 changes: 61 additions & 0 deletions principles/karpathy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Andrej Karpathy's Coding Principles

## Principle 1: Think Before Coding

Before writing a single line of code, think through the problem thoroughly. Understand the requirements, design the approach, and consider edge cases. Most coding time should be spent thinking, not typing. A clear mental model prevents rework and produces cleaner solutions.

Ask yourself:
- What exactly am I trying to accomplish?
- What are the constraints and edge cases?
- What is the simplest approach that could work?
- How will I verify correctness?

## Principle 1 (Reviewer Variant): Think Before Judging

Before forming judgments about code quality, take time to understand the full context. Consider the constraints the implementer was working under, the trade-offs they had to make, and the requirements they were given. A hasty judgment misses nuance; a considered judgment improves the codebase.

Ask yourself:
- What was the implementer trying to accomplish?
- What constraints and trade-offs shaped this implementation?
- Is the issue a real problem or a matter of style preference?
- What context might I be missing?

## Principle 1 (Argus Variant): Think Before Analyzing

Before analyzing any content, take time to observe thoroughly. Let the full picture form before drawing conclusions. Surface-level analysis misses patterns; deep observation reveals insights that matter.

Ask yourself:
- What am I actually looking at? What is the full scope?
- What patterns emerge across the whole, not just the parts?
- What is the context surrounding this content?
- What details might be significant that are easy to overlook?

## Principle 2: Simplicity First

Always reach for the simplest solution first. Simple code is easier to understand, debug, test, and extend. Resist the urge to build elaborate abstractions or optimize prematurely. Complexity should be earned — only introduce it when the simple solution demonstrably falls short.

Guidelines:
- Write code a junior engineer can understand
- Avoid premature abstraction and optimization
- Delete code whenever possible — less code is better code
- Favor boring, proven patterns over clever, novel ones

## Principle 3: Surgical Changes

Make the smallest possible change to achieve the goal. Each change should do exactly one thing, and do it well. Do not refactor unrelated code, fix unrelated bugs, or add "while I'm here" improvements. Precise, minimal changes reduce risk and make review straightforward.

Guidelines:
- One logical change per commit/PR
- Don't mix refactoring with feature work
- Leave the codebase cleaner than you found it — but only in the area you're touching
- If you see something broken that's out of scope, file an issue, don't fix it inline

## Principle 4: Goal-Driven Execution

Stay relentlessly focused on the goal. Do not chase shiny objects, explore interesting tangents, or get sidetracked by adjacent improvements. Every action should trace back to the acceptance criteria. If it's not required to meet the goal, it's a distraction.

Guidelines:
- Before every action, ask: "Does this directly advance the goal?"
- Track progress against acceptance criteria, not against interesting side quests
- Timebox exploration — if you need to research, set a limit and return to the goal
- Ship the minimum viable implementation, then iterate
106 changes: 106 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { beforeAll, describe, expect, test } from "bun:test";
import type { Config } from "@opencode-ai/plugin";
import { OpenCodeToolbox } from "./index";

/**
* RED phase: Test that principles are prepended to agent prompts based on agent mapping.
* This test will FAIL until the injection code is implemented in src/index.ts.
*/
describe("Karpathy Principles Injection", () => {
let result: { config?: (cfg: Config) => Promise<void> } | undefined;

beforeAll(async () => {
result = await OpenCodeToolbox({ directory: "." } as any);

Check warning on line 13 in src/index.test.ts

View workflow job for this annotation

GitHub Actions / check

lint/suspicious/noExplicitAny

Unexpected any. Specify a different type.
});

test("implementer gets all four principles with Think Before Coding", async () => {
const cfg = { agent: {}, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const implPrompt = prompt.implementer?.prompt ?? "";

expect(implPrompt).toContain("Think Before Coding");
expect(implPrompt).toContain("Simplicity First");
expect(implPrompt).toContain("Surgical Changes");
expect(implPrompt).toContain("Goal-Driven Execution");
});

test("general gets all four principles with Think Before Coding", async () => {
const cfg = { agent: { general: {} }, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const genPrompt = prompt.general?.prompt ?? "";

expect(genPrompt).toContain("Think Before Coding");
expect(genPrompt).toContain("Simplicity First");
expect(genPrompt).toContain("Surgical Changes");
expect(genPrompt).toContain("Goal-Driven Execution");
});

test("reviewer gets principles 1(variant),2,4 — Think Before Judging, not Think Before Coding", async () => {
const cfg = { agent: { reviewer: {} }, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const revPrompt = prompt.reviewer?.prompt ?? "";

// Should have the judging variant
expect(revPrompt).toContain("Think Before Judging");
// Should have principles 2 and 4
expect(revPrompt).toContain("Simplicity First");
expect(revPrompt).toContain("Goal-Driven Execution");
// Should NOT have principle 3 (Surgical Changes)
expect(revPrompt).not.toContain("Surgical Changes");
// Should NOT have the coder variant
expect(revPrompt).not.toContain("Think Before Coding");
});

test("argus gets principles 1(variant),2,4 — Think Before Analyzing", async () => {
const cfg = { agent: { argus: {} }, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const argusPrompt = prompt.argus?.prompt ?? "";

// Should have the analyzing variant
expect(argusPrompt).toContain("Think Before Analyzing");
// Should have principles 2 and 4
expect(argusPrompt).toContain("Simplicity First");
expect(argusPrompt).toContain("Goal-Driven Execution");
// Should NOT have principle 3
expect(argusPrompt).not.toContain("Surgical Changes");
// Should NOT have the coder or judging variants
expect(argusPrompt).not.toContain("Think Before Coding");
expect(argusPrompt).not.toContain("Think Before Judging");
});

test("explore gets no principles", async () => {
const cfg = { agent: { explore: {} }, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const explorePrompt = prompt.explore?.prompt ?? "";

// explore should NOT get any principles
expect(explorePrompt).not.toContain("Think Before Coding");
expect(explorePrompt).not.toContain("Think Before Judging");
expect(explorePrompt).not.toContain("Think Before Analyzing");
expect(explorePrompt).not.toContain("Simplicity First");
expect(explorePrompt).not.toContain("Surgical Changes");
expect(explorePrompt).not.toContain("Goal-Driven Execution");
});

test("principles are prepended (appear at start of agent prompt)", async () => {
const cfg = { agent: { implementer: {} }, skills: { paths: [] } } as unknown as Config & Record<string, unknown>;
await result?.config?.(cfg as Config);

const prompt = (cfg as Record<string, unknown>).agent as Record<string, { prompt: string }>;
const implPrompt = prompt.implementer?.prompt ?? "";

// Principles header should be at the very beginning of the prompt
const headerIndex = implPrompt.indexOf("# Andrej Karpathy's Coding Principles");
expect(headerIndex).toBe(0);
});
});
90 changes: 90 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,70 @@ interface CommandConfig {
[key: string]: unknown;
}

// ── Karpathy Principles ───────────────────────────────────────────

interface PrincipleSections {
v1Coding: string;
v1Judging: string;
v1Analyzing: string;
v2: string;
v3: string;
v4: string;
}

function parsePrinciples(content: string): PrincipleSections {
const sections: Record<string, string> = {};
// Split by "## Principle" headers; skip the intro before the first header
const parts = content.split(/(?=^## Principle)/m);
for (const part of parts) {
const headerMatch = part.match(/^## Principle\s+(\d).*?\n/);
if (!headerMatch) continue;
const num = headerMatch[1];
const body = part.slice(headerMatch[0].length).trim();

if (num === "1") {
if (part.includes("Reviewer Variant")) {
sections.v1Judging = body;
} else if (part.includes("Argus Variant")) {
sections.v1Analyzing = body;
} else {
sections.v1Coding = body;
}
} else {
sections[`v${num}`] = body;
}
}
return sections as unknown as PrincipleSections;
}

const AGENT_PRINCIPLE_MAP: Record<string, (keyof PrincipleSections)[]> = {
implementer: ["v1Coding", "v2", "v3", "v4"],
general: ["v1Coding", "v2", "v3", "v4"],
reviewer: ["v1Judging", "v2", "v4"],
argus: ["v1Analyzing", "v2", "v4"],
};

const HEADER_TEMPLATES: Record<string, string> = {
v1Coding: "## Principle 1: Think Before Coding",
v1Judging: "## Principle 1: Think Before Judging",
v1Analyzing: "## Principle 1: Think Before Analyzing",
v2: "## Principle 2: Simplicity First",
v3: "## Principle 3: Surgical Changes",
v4: "## Principle 4: Goal-Driven Execution",
};

function buildPrinciplesBlock(sections: PrincipleSections, agentName: string): string {
const keys = AGENT_PRINCIPLE_MAP[agentName];
if (!keys || keys.length === 0) return "";

const blocks = keys.map((key) => {
const header = HEADER_TEMPLATES[key];
const body = sections[key] ?? "";
return `${header}\n\n${body}`;
});
return `# Andrej Karpathy's Coding Principles\n\n${blocks.join("\n\n")}\n\n---\n\n`;
}

function readMarkdownConfigs(dirPath: string): Record<string, FrontmatterEntry> {
const result: Record<string, FrontmatterEntry> = {};
if (!fs.existsSync(dirPath)) return result;
Expand Down Expand Up @@ -100,6 +164,15 @@ export const OpenCodeToolbox: Plugin = async ({ directory: _directory }) => {
};
const upstreamCommandConfigs = buildCommandConfigs(upstreamCommandsRaw);

// ── Karpathy principles ───────────────────────────────────────
const principlesPath = path.resolve(__dirname, "principles", "karpathy.md");
const primaryPrinciplesPath = path.resolve(__dirname, "principles", "karpathy-primary.md");
let principleSections: PrincipleSections | null = null;
if (fs.existsSync(principlesPath)) {
const rawPrinciples = fs.readFileSync(principlesPath, "utf8");
principleSections = parsePrinciples(rawPrinciples);
}

return {
config: async (config) => {
const cfg = config as DynamicConfig;
Expand All @@ -118,6 +191,23 @@ export const OpenCodeToolbox: Plugin = async ({ directory: _directory }) => {

cfg.agent = { ...(cfg.agent ?? {}), ...agentConfigs };
cfg.command = { ...upstreamCommandConfigs, ...commandConfigs, ...(cfg.command ?? {}) };

// Prepend Karpathy principles to agent prompts based on agent mapping
if (principleSections) {
for (const [agentName, agentCfg] of Object.entries(cfg.agent)) {
if (!agentCfg) continue;
const block = buildPrinciplesBlock(principleSections, agentName);
if (block) {
agentCfg.prompt = block + (agentCfg.prompt ?? "");
}
}
}

// Primary agent: inject full Karpathy principles via instructions
cfg.instructions = cfg.instructions || [];
if (!cfg.instructions.includes(primaryPrinciplesPath)) {
cfg.instructions.push(primaryPrinciplesPath);
}
},
};
};
Loading