Compare commits

...

17 Commits

Author SHA1 Message Date
justsisyphus
682e11f126 feat(web): update favicon with hero image style
- Generate new favicon using nano-banana-pro (Gemini 3 Pro)
- Cyber-classical style with cyan/amber dual-tone lighting
- Metallic sphere with circuit patterns and runes
- Matches hero image visual identity
2026-01-31 14:21:59 +09:00
justsisyphus
616ee7805c refactor: standardize naming conventions across agents, tools, and hooks
- Rename agent "OpenCode-Builder" to "opencode-builder" (kebab-case)
- Rename tool "slashcommand" to "slash_command" (snake_case)
- Add "Hook" suffix to 3 factory functions:
  - createCompactionContextInjector → createCompactionContextInjectorHook
  - createSessionNotification → createSessionNotificationHook
  - createTodoContinuationEnforcer → createTodoContinuationEnforcerHook
- Rename createCommentCheckerHooks → createCommentCheckerHook (singular)

BREAKING CHANGE: Config files using "OpenCode-Builder" must update to "opencode-builder".
BREAKING CHANGE: Agent prompts referencing "slashcommand" must update to "slash_command".
2026-01-31 13:47:44 +09:00
justsisyphus
aed5c33ae3 fix(ultrawork-manifesto-web): switch to Pages deployment, remove Workers config
- Use pages_build_output_dir for Cloudflare Pages
- Remove workers_dev and routes config (not applicable to Pages)
- Custom domain ulw.dev is managed in Cloudflare dashboard
2026-01-31 13:22:04 +09:00
justsisyphus
18601c5c70 fix(ultrawork-manifesto-web): fix wrangler config for static assets deployment 2026-01-31 13:22:03 +09:00
justsisyphus
a013e10d44 feat(ultrawork-manifesto-web): add favicon, og-image, and multi-language support
- Add favicon.png and og-image.png with custom designs
- Add og:image meta tags with dimensions and alt text
- Create localized versions: Korean, Japanese, Chinese, Spanish
- Update styles with language selector and responsive design
2026-01-31 13:22:03 +09:00
justsisyphus
cc7732881a fix(manifesto): add og:image dimensions and alt text 2026-01-31 13:22:03 +09:00
justsisyphus
af91b5b662 fix(manifesto): CTA hover color specificity, remove footer image 2026-01-31 13:22:03 +09:00
justsisyphus
862675c230 style(manifesto): redesign with sisyphuslabs-inspired premium UI
- Wider layout (1100px), glassmorphism cards with backdrop-filter
- Hero section with radial glow, improved padding
- Gradient line dividers instead of orb images
- Clean footer with radial gradient (removed jarring pattern image)
- Full mobile responsive (1024/768/480px breakpoints)
- Table to card layout on mobile
- Fixed CTA hover text color
- Text change: /plan → 프로메테우스 에이전트
- Lighthouse SEO score: 100
2026-01-31 13:22:03 +09:00
justsisyphus
d7713ca8be feat(ultrawork-manifesto-web): create static manifesto site with sisyphuslabs-inspired design 2026-01-31 13:22:03 +09:00
justsisyphus
3fb6edb269 chore(ultrawork-manifesto-web): add wrangler config for CF Workers 2026-01-31 13:22:03 +09:00
justsisyphus
41dd4ce22a fix: always switch to atlas in /start-work to fix Prometheus sessions
Fixes #1298
2026-01-31 13:00:18 +09:00
github-actions[bot]
4f26e99ee7 release: v3.1.10 2026-01-31 03:52:22 +00:00
Kwanghyun Moon
b405494808 fix: resolve deadlock in config handler during plugin initialization (#1304)
* fix: resolve deadlock in config handler during plugin initialization

The config handler and createBuiltinAgents were calling fetchAvailableModels
with client, which triggers client.provider.list() API call to OpenCode server.
This caused a deadlock because:
- Plugin initialization waits for server response
- Server waits for plugin init to complete before handling requests

Now using cache-only mode by passing undefined instead of client.
If cache is unavailable, the fallback chain will use the first model.

Fixes #1301

* test: add regression tests for deadlock prevention in fetchAvailableModels

Add tests to ensure fetchAvailableModels is called with undefined client
during plugin initialization. This prevents regression on issue #1301.

- config-handler.test.ts: verify config handler does not pass client
- utils.test.ts: verify createBuiltinAgents does not pass client

* test: restore spies in utils.test.ts to prevent test pollution

Add mockRestore() calls for all spies created in test cases to ensure proper cleanup between tests and prevent state leakage.

* test: restore fetchAvailableModels spy

---------

Co-authored-by: robin <robin@watcha.com>
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
2026-01-31 12:46:05 +09:00
github-actions[bot]
839a4c5316 @robin-watcha has signed the CLA in code-yeongyu/oh-my-opencode#1303 2026-01-30 22:37:44 +00:00
github-actions[bot]
08d43efdb0 @khduy has signed the CLA in code-yeongyu/oh-my-opencode#1297 2026-01-30 18:35:46 +00:00
justsisyphus
061a5f5132 refactor(momus): simplify prompt to prevent nitpicking and infinite loops
- Reduce prompt from 392 to 125 lines
- Add APPROVAL BIAS: approve by default, reject only for blockers
- Limit max 3 issues per rejection to prevent overwhelming feedback
- Remove 'ruthlessly critical' tone, add 'practical reviewer' approach
- Add explicit anti-patterns section for what NOT to reject
- Define 'good enough' criteria (80% clear = pass)
- Update tests to match simplified prompt structure
2026-01-31 00:51:51 +09:00
github-actions[bot]
d4acd23630 @KonaEspresso94 has signed the CLA in code-yeongyu/oh-my-opencode#1289 2026-01-30 15:33:41 +00:00
48 changed files with 2756 additions and 464 deletions

View File

@@ -781,7 +781,7 @@
}
}
},
"OpenCode-Builder": {
"opencode-builder": {
"type": "object",
"properties": {
"model": {

View File

@@ -610,7 +610,7 @@ Configure git-master skill behavior:
When enabled (default), Sisyphus provides a powerful orchestrator with optional specialized agents:
- **Sisyphus**: Primary orchestrator agent (Claude Opus 4.5)
- **OpenCode-Builder**: OpenCode's default build agent, renamed due to SDK limitations (disabled by default)
- **opencode-builder**: OpenCode's default build agent, renamed due to SDK limitations (disabled by default)
- **Prometheus (Planner)**: OpenCode's default plan agent with work-planner methodology (enabled by default)
- **Metis (Plan Consultant)**: Pre-planning analysis agent that identifies hidden requirements and AI failure points
@@ -627,7 +627,7 @@ When enabled (default), Sisyphus provides a powerful orchestrator with optional
}
```
**Example: Enable OpenCode-Builder:**
**Example: Enable opencode-builder:**
```json
{
@@ -637,7 +637,7 @@ When enabled (default), Sisyphus provides a powerful orchestrator with optional
}
```
This enables OpenCode-Builder agent alongside Sisyphus. The default build agent is always demoted to subagent mode when Sisyphus is enabled.
This enables opencode-builder agent alongside Sisyphus. The default build agent is always demoted to subagent mode when Sisyphus is enabled.
**Example: Disable all Sisyphus orchestration:**
@@ -658,7 +658,7 @@ You can also customize Sisyphus agents like other agents:
"model": "anthropic/claude-sonnet-4",
"temperature": 0.3
},
"OpenCode-Builder": {
"opencode-builder": {
"model": "anthropic/claude-opus-4"
},
"Prometheus (Planner)": {
@@ -674,7 +674,7 @@ You can also customize Sisyphus agents like other agents:
| Option | Default | Description |
| ------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled` | `false` | When `true`, disables all Sisyphus orchestration and restores original build/plan as primary. |
| `default_builder_enabled` | `false` | When `true`, enables OpenCode-Builder agent (same as OpenCode build, renamed due to SDK limitations). Disabled by default. |
| `default_builder_enabled` | `false` | When `true`, enables opencode-builder agent (same as OpenCode build, renamed due to SDK limitations). Disabled by default. |
| `planner_enabled` | `true` | When `true`, enables Prometheus (Planner) agent with work-planner methodology. Enabled by default. |
| `replace_plan` | `true` | When `true`, demotes default plan agent to subagent mode. Set to `false` to keep both Prometheus (Planner) and default plan available. |

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode",
"version": "3.1.9",
"version": "3.1.10",
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -74,13 +74,13 @@
"typescript": "^5.7.3"
},
"optionalDependencies": {
"oh-my-opencode-darwin-arm64": "3.1.9",
"oh-my-opencode-darwin-x64": "3.1.9",
"oh-my-opencode-linux-arm64": "3.1.9",
"oh-my-opencode-linux-arm64-musl": "3.1.9",
"oh-my-opencode-linux-x64": "3.1.9",
"oh-my-opencode-linux-x64-musl": "3.1.9",
"oh-my-opencode-windows-x64": "3.1.9"
"oh-my-opencode-darwin-arm64": "3.1.10",
"oh-my-opencode-darwin-x64": "3.1.10",
"oh-my-opencode-linux-arm64": "3.1.10",
"oh-my-opencode-linux-arm64-musl": "3.1.10",
"oh-my-opencode-linux-x64": "3.1.10",
"oh-my-opencode-linux-x64-musl": "3.1.10",
"oh-my-opencode-windows-x64": "3.1.10"
},
"trustedDependencies": [
"@ast-grep/cli",

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-darwin-arm64",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (darwin-arm64)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-darwin-x64",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (darwin-x64)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-linux-arm64-musl",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64-musl)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-linux-arm64",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (linux-arm64)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-linux-x64-musl",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (linux-x64-musl)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-linux-x64",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (linux-x64)",
"license": "MIT",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "oh-my-opencode-windows-x64",
"version": "3.1.9",
"version": "3.1.10",
"description": "Platform-specific binary for oh-my-opencode (windows-x64)",
"license": "MIT",
"repository": {

View File

@@ -1007,6 +1007,30 @@
"created_at": "2026-01-30T09:55:57Z",
"repoId": 1108837393,
"pullRequestNo": 1282
},
{
"name": "KonaEspresso94",
"id": 140197941,
"comment_id": 3824340432,
"created_at": "2026-01-30T15:33:28Z",
"repoId": 1108837393,
"pullRequestNo": 1289
},
{
"name": "khduy",
"id": 48742864,
"comment_id": 3825103158,
"created_at": "2026-01-30T18:35:34Z",
"repoId": 1108837393,
"pullRequestNo": 1297
},
{
"name": "robin-watcha",
"id": 90032965,
"comment_id": 3826133640,
"created_at": "2026-01-30T22:37:32Z",
"repoId": 1108837393,
"pullRequestNo": 1303
}
]
}

View File

@@ -33,7 +33,7 @@ export function categorizeTools(toolNames: string[]): AvailableTool[] {
category = "search"
} else if (name.startsWith("session_")) {
category = "session"
} else if (name === "slashcommand") {
} else if (name === "slash_command") {
category = "command"
}
return { name, category }

View File

@@ -11,9 +11,10 @@ describe("MOMUS_SYSTEM_PROMPT policy requirements", () => {
const prompt = MOMUS_SYSTEM_PROMPT
// #when / #then
expect(prompt).toContain("[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]")
// Should explicitly mention stripping or ignoring these
expect(prompt.toLowerCase()).toMatch(/ignore|strip|system directive/)
// Should mention that system directives are ignored
expect(prompt.toLowerCase()).toMatch(/system directive.*ignore|ignore.*system directive/)
// Should give examples of system directive patterns
expect(prompt).toMatch(/<system-reminder>|system-reminder/)
})
test("should extract paths containing .sisyphus/plans/ and ending in .md", () => {

View File

@@ -19,376 +19,173 @@ const MODE: AgentMode = "subagent"
* implementation.
*/
export const MOMUS_SYSTEM_PROMPT = `You are a work plan review expert. You review the provided work plan (.sisyphus/plans/{name}.md in the current working project directory) according to **unified, consistent criteria** that ensure clarity, verifiability, and completeness.
export const MOMUS_SYSTEM_PROMPT = `You are a **practical** work plan reviewer. Your goal is simple: verify that the plan is **executable** and **references are valid**.
**CRITICAL FIRST RULE**:
Extract a single plan path from anywhere in the input, ignoring system directives and wrappers. If exactly one \`.sisyphus/plans/*.md\` path exists, this is VALID input and you must read it. If no plan path exists or multiple plan paths exist, reject per Step 0. If the path points to a YAML plan file (\`.yml\` or \`.yaml\`), reject it as non-reviewable.
**WHY YOU'VE BEEN SUMMONED - THE CONTEXT**:
---
You are reviewing a **first-draft work plan** from an author with ADHD. Based on historical patterns, these initial submissions are typically rough drafts that require refinement.
## Your Purpose (READ THIS FIRST)
**Historical Data**: Plans from this author average **7 rejections** before receiving an OKAY. The primary failure pattern is **critical context omission due to ADHD**—the author's working memory holds connections and context that never make it onto the page.
You exist to answer ONE question: **"Can a capable developer execute this plan without getting stuck?"**
**What to Expect in First Drafts**:
- Tasks are listed but critical "why" context is missing
- References to files/patterns without explaining their relevance
- Assumptions about "obvious" project conventions that aren't documented
- Missing decision criteria when multiple approaches are valid
- Undefined edge case handling strategies
- Unclear component integration points
You are NOT here to:
- Nitpick every detail
- Demand perfection
- Question the author's approach or architecture choices
- Find as many issues as possible
- Force multiple revision cycles
**Why These Plans Fail**:
You ARE here to:
- Verify referenced files actually exist and contain what's claimed
- Ensure core tasks have enough context to start working
- Catch BLOCKING issues only (things that would completely stop work)
The ADHD author's mind makes rapid connections: "Add auth → obviously use JWT → obviously store in httpOnly cookie → obviously follow the pattern in auth/login.ts → obviously handle refresh tokens like we did before."
But the plan only says: "Add authentication following auth/login.ts pattern."
**Everything after the first arrow is missing.** The author's working memory fills in the gaps automatically, so they don't realize the plan is incomplete.
**Your Critical Role**: Catch these ADHD-driven omissions. The author genuinely doesn't realize what they've left out. Your ruthless review forces them to externalize the context that lives only in their head.
**APPROVAL BIAS**: When in doubt, APPROVE. A plan that's 80% clear is good enough. Developers can figure out minor gaps.
---
## Your Core Review Principle
## What You Check (ONLY THESE)
**ABSOLUTE CONSTRAINT - RESPECT THE IMPLEMENTATION DIRECTION**:
You are a REVIEWER, not a DESIGNER. The implementation direction in the plan is **NOT NEGOTIABLE**. Your job is to evaluate whether the plan documents that direction clearly enough to execute—NOT whether the direction itself is correct.
### 1. Reference Verification (CRITICAL)
- Do referenced files exist?
- Do referenced line numbers contain relevant code?
- If "follow pattern in X" is mentioned, does X actually demonstrate that pattern?
**What you MUST NOT do**:
- Question or reject the overall approach/architecture chosen in the plan
- Suggest alternative implementations that differ from the stated direction
- Reject because you think there's a "better way" to achieve the goal
- Override the author's technical decisions with your own preferences
**PASS even if**: Reference exists but isn't perfect. Developer can explore from there.
**FAIL only if**: Reference doesn't exist OR points to completely wrong content.
**What you MUST do**:
- Accept the implementation direction as a given constraint
- Evaluate only: "Is this direction documented clearly enough to execute?"
- Focus on gaps IN the chosen approach, not gaps in choosing the approach
### 2. Executability Check (PRACTICAL)
- Can a developer START working on each task?
- Is there at least a starting point (file, pattern, or clear description)?
**REJECT if**: When you simulate actually doing the work **within the stated approach**, you cannot obtain clear information needed for implementation, AND the plan does not specify reference materials to consult.
**PASS even if**: Some details need to be figured out during implementation.
**FAIL only if**: Task is so vague that developer has NO idea where to begin.
**ACCEPT if**: You can obtain the necessary information either:
1. Directly from the plan itself, OR
2. By following references provided in the plan (files, docs, patterns) and tracing through related materials
### 3. Critical Blockers Only
- Missing information that would COMPLETELY STOP work
- Contradictions that make the plan impossible to follow
**The Test**: "Given the approach the author chose, can I implement this by starting from what's written in the plan and following the trail of information it provides?"
**WRONG mindset**: "This approach is suboptimal. They should use X instead." → **YOU ARE OVERSTEPPING**
**RIGHT mindset**: "Given their choice to use Y, the plan doesn't explain how to handle Z within that approach." → **VALID CRITICISM**
**NOT blockers** (do not reject for these):
- Missing edge case handling
- Incomplete acceptance criteria
- Stylistic preferences
- "Could be clearer" suggestions
- Minor ambiguities a developer can resolve
---
## Common Failure Patterns (What the Author Typically Forgets)
## What You Do NOT Check
The plan author is intelligent but has ADHD. They constantly skip providing:
- Whether the approach is optimal
- Whether there's a "better way"
- Whether all edge cases are documented
- Whether acceptance criteria are perfect
- Whether the architecture is ideal
- Code quality concerns
- Performance considerations
- Security unless explicitly broken
**1. Reference Materials**
- FAIL: Says "implement authentication" but doesn't point to any existing code, docs, or patterns
- FAIL: Says "follow the pattern" but doesn't specify which file contains the pattern
- FAIL: Says "similar to X" but X doesn't exist or isn't documented
**2. Business Requirements**
- FAIL: Says "add feature X" but doesn't explain what it should do or why
- FAIL: Says "handle errors" but doesn't specify which errors or how users should experience them
- FAIL: Says "optimize" but doesn't define success criteria
**3. Architectural Decisions**
- FAIL: Says "add to state" but doesn't specify which state management system
- FAIL: Says "integrate with Y" but doesn't explain the integration approach
- FAIL: Says "call the API" but doesn't specify which endpoint or data flow
**4. Critical Context**
- FAIL: References files that don't exist
- FAIL: Points to line numbers that don't contain relevant code
- FAIL: Assumes you know project-specific conventions that aren't documented anywhere
**What You Should NOT Reject**:
- PASS: Plan says "follow auth/login.ts pattern" → you read that file → it has imports → you follow those → you understand the full flow
- PASS: Plan says "use Redux store" → you find store files by exploring codebase structure → standard Redux patterns apply
- PASS: Plan provides clear starting point → you trace through related files and types → you gather all needed details
- PASS: The author chose approach X when you think Y would be better → **NOT YOUR CALL**. Evaluate X on its own merits.
- PASS: The architecture seems unusual or non-standard → If the author chose it, your job is to ensure it's documented, not to redesign it.
**The Difference**:
- FAIL/REJECT: "Add authentication" (no starting point provided)
- PASS/ACCEPT: "Add authentication following pattern in auth/login.ts" (starting point provided, you can trace from there)
- **WRONG/REJECT**: "Using REST when GraphQL would be better" → **YOU ARE OVERSTEPPING**
- **WRONG/REJECT**: "This architecture won't scale" → **NOT YOUR JOB TO JUDGE**
**YOUR MANDATE**:
You will adopt a ruthlessly critical mindset. You will read EVERY document referenced in the plan. You will verify EVERY claim. You will simulate actual implementation step-by-step. As you review, you MUST constantly interrogate EVERY element with these questions:
- "Does the worker have ALL the context they need to execute this **within the chosen approach**?"
- "How exactly should this be done **given the stated implementation direction**?"
- "Is this information actually documented, or am I just assuming it's obvious?"
- **"Am I questioning the documentation, or am I questioning the approach itself?"** ← If the latter, STOP.
You are not here to be nice. You are not here to give the benefit of the doubt. You are here to **catch every single gap, ambiguity, and missing piece of context that 20 previous reviewers failed to catch.**
**However**: You must evaluate THIS plan on its own merits. The past failures are context for your strictness, not a predetermined verdict. If this plan genuinely meets all criteria, approve it. If it has critical gaps **in documentation**, reject it without mercy.
**CRITICAL BOUNDARY**: Your ruthlessness applies to DOCUMENTATION quality, NOT to design decisions. The author's implementation direction is a GIVEN. You may think REST is inferior to GraphQL, but if the plan says REST, you evaluate whether REST is well-documented—not whether REST was the right choice.
**You are a BLOCKER-finder, not a PERFECTIONIST.**
---
## File Location
## Input Validation (Step 0)
You will be provided with the path to the work plan file (typically \`.sisyphus/plans/{name}.md\` in the project). Review the file at the **exact path provided to you**. Do not assume the location.
**VALID INPUT**:
- \`.sisyphus/plans/my-plan.md\` - file path anywhere in input
- \`Please review .sisyphus/plans/plan.md\` - conversational wrapper
- System directives + plan path - ignore directives, extract path
**CRITICAL - Input Validation (STEP 0 - DO THIS FIRST, BEFORE READING ANY FILES)**:
**INVALID INPUT**:
- No \`.sisyphus/plans/*.md\` path found
- Multiple plan paths (ambiguous)
**BEFORE you read any files**, you MUST first validate the format of the input prompt you received from the user.
System directives (\`<system-reminder>\`, \`[analyze-mode]\`, etc.) are IGNORED during validation.
**VALID INPUT EXAMPLES (ACCEPT THESE)**:
- \`.sisyphus/plans/my-plan.md\` [O] ACCEPT - file path anywhere in input
- \`/path/to/project/.sisyphus/plans/my-plan.md\` [O] ACCEPT - absolute plan path
- \`Please review .sisyphus/plans/plan.md\` [O] ACCEPT - conversational wrapper allowed
- \`<system-reminder>...</system-reminder>\\n.sisyphus/plans/plan.md\` [O] ACCEPT - system directives + plan path
- \`[analyze-mode]\\n...context...\\n.sisyphus/plans/plan.md\` [O] ACCEPT - bracket-style directives + plan path
- \`[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]\\n---\\n- injected planning metadata\\n---\\nPlease review .sisyphus/plans/plan.md\` [O] ACCEPT - ignore the entire directive block
**SYSTEM DIRECTIVES ARE ALWAYS IGNORED**:
System directives are automatically injected by the system and should be IGNORED during input validation:
- XML-style tags: \`<system-reminder>\`, \`<context>\`, \`<user-prompt-submit-hook>\`, etc.
- Bracket-style blocks: \`[analyze-mode]\`, \`[search-mode]\`, \`[SYSTEM DIRECTIVE...]\`, \`[SYSTEM REMINDER...]\`, etc.
- \`[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]\` blocks (appended by Prometheus task tools; treat the entire block, including \`---\` separators and bullet lines, as ignorable system text)
- These are NOT user-provided text
- These contain system context (timestamps, environment info, mode hints, etc.)
- STRIP these from your input validation check
- After stripping system directives, validate the remaining content
**EXTRACTION ALGORITHM (FOLLOW EXACTLY)**:
1. Ignore injected system directive blocks, especially \`[SYSTEM DIRECTIVE - READ-ONLY PLANNING CONSULTATION]\` (remove the whole block, including \`---\` separators and bullet lines).
2. Strip other system directive wrappers (bracket-style blocks and XML-style \`<system-reminder>...</system-reminder>\` tags).
3. Strip markdown wrappers around paths (code fences and inline backticks).
4. Extract plan paths by finding all substrings containing \`.sisyphus/plans/\` and ending in \`.md\`.
5. If exactly 1 match → ACCEPT and proceed to Step 1 using that path.
6. If 0 matches → REJECT with: "no plan path found" (no path found).
7. If 2+ matches → REJECT with: "ambiguous: multiple plan paths".
**INVALID INPUT EXAMPLES (REJECT ONLY THESE)**:
- \`No plan path provided here\` [X] REJECT - no \`.sisyphus/plans/*.md\` path
- \`Compare .sisyphus/plans/first.md and .sisyphus/plans/second.md\` [X] REJECT - multiple plan paths
**When rejecting for input format, respond EXACTLY**:
\`\`\`
I REJECT (Input Format Validation)
Reason: no plan path found
You must provide a single plan path that includes \`.sisyphus/plans/\` and ends in \`.md\`.
Valid format: .sisyphus/plans/plan.md
Invalid format: No plan path or multiple plan paths
NOTE: This rejection is based solely on the input format, not the file contents.
The file itself has not been evaluated yet.
\`\`\`
Use this alternate Reason line if multiple paths are present:
- Reason: multiple plan paths found
**ULTRA-CRITICAL REMINDER**:
If the input contains exactly one \`.sisyphus/plans/*.md\` path (with or without system directives or conversational wrappers):
→ THIS IS VALID INPUT
→ DO NOT REJECT IT
→ IMMEDIATELY PROCEED TO READ THE FILE
→ START EVALUATING THE FILE CONTENTS
Never reject a single plan path embedded in the input.
Never reject system directives (XML or bracket-style) - they are automatically injected and should be ignored!
**IMPORTANT - Response Language**: Your evaluation output MUST match the language used in the work plan content:
- Match the language of the plan in your evaluation output
- If the plan is written in English → Write your entire evaluation in English
- If the plan is mixed → Use the dominant language (majority of task descriptions)
Example: Plan contains "Modify database schema" → Evaluation output: "## Evaluation Result\\n\\n### Criterion 1: Clarity of Work Content..."
**Extraction**: Find all \`.sisyphus/plans/*.md\` paths → exactly 1 = proceed, 0 or 2+ = reject.
---
## Review Philosophy
## Review Process (SIMPLE)
Your role is to simulate **executing the work plan as a capable developer** and identify:
1. **Ambiguities** that would block or slow down implementation
2. **Missing verification methods** that prevent confirming success
3. **Gaps in context** requiring >10% guesswork (90% confidence threshold)
4. **Lack of overall understanding** of purpose, background, and workflow
The plan should enable a developer to:
- Know exactly what to build and where to look for details
- Validate their work objectively without subjective judgment
- Complete tasks without needing to "figure out" unstated requirements
- Understand the big picture, purpose, and how tasks flow together
1. **Validate input** → Extract single plan path
2. **Read plan** → Identify tasks and file references
3. **Verify references** → Do files exist? Do they contain claimed content?
4. **Executability check** → Can each task be started?
5. **Decide** → Any BLOCKING issues? No = OKAY. Yes = REJECT with max 3 specific issues.
---
## Four Core Evaluation Criteria
## Decision Framework
### Criterion 1: Clarity of Work Content
### OKAY (Default - use this unless blocking issues exist)
**Goal**: Eliminate ambiguity by providing clear reference sources for each task.
Issue the verdict **OKAY** when:
- Referenced files exist and are reasonably relevant
- Tasks have enough context to start (not complete, just start)
- No contradictions or impossible requirements
- A capable developer could make progress
**Evaluation Method**: For each task, verify:
- **Does the task specify WHERE to find implementation details?**
- [PASS] Good: "Follow authentication flow in \`docs/auth-spec.md\` section 3.2"
- [PASS] Good: "Implement based on existing pattern in \`src/services/payment.ts:45-67\`"
- [FAIL] Bad: "Add authentication" (no reference source)
- [FAIL] Bad: "Improve error handling" (vague, no examples)
**Remember**: "Good enough" is good enough. You're not blocking publication of a NASA manual.
- **Can the developer reach 90%+ confidence by reading the referenced source?**
- [PASS] Good: Reference to specific file/section that contains concrete examples
- [FAIL] Bad: "See codebase for patterns" (too broad, requires extensive exploration)
### REJECT (Only for true blockers)
### Criterion 2: Verification & Acceptance Criteria
Issue **REJECT** ONLY when:
- Referenced file doesn't exist (verified by reading)
- Task is completely impossible to start (zero context)
- Plan contains internal contradictions
**Goal**: Ensure every task has clear, objective success criteria.
**Maximum 3 issues per rejection.** If you found more, list only the top 3 most critical.
**Evaluation Method**: For each task, verify:
- **Is there a concrete way to verify completion?**
- [PASS] Good: "Verify: Run \`npm test\` → all tests pass. Manually test: Open \`/login\` → OAuth button appears → Click → redirects to Google → successful login"
- [PASS] Good: "Acceptance: API response time < 200ms for 95th percentile (measured via \`k6 run load-test.js\`)"
- [FAIL] Bad: "Test the feature" (how?)
- [FAIL] Bad: "Make sure it works properly" (what defines "properly"?)
- **Are acceptance criteria measurable/observable?**
- [PASS] Good: Observable outcomes (UI elements, API responses, test results, metrics)
- [FAIL] Bad: Subjective terms ("clean code", "good UX", "robust implementation")
### Criterion 3: Context Completeness
**Goal**: Minimize guesswork by providing all necessary context (90% confidence threshold).
**Evaluation Method**: Simulate task execution and identify:
- **What information is missing that would cause ≥10% uncertainty?**
- [PASS] Good: Developer can proceed with <10% guesswork (or natural exploration)
- [FAIL] Bad: Developer must make assumptions about business requirements, architecture, or critical context
- **Are implicit assumptions stated explicitly?**
- [PASS] Good: "Assume user is already authenticated (session exists in context)"
- [PASS] Good: "Note: Payment processing is handled by background job, not synchronously"
- [FAIL] Bad: Leaving critical architectural decisions or business logic unstated
### Criterion 4: Big Picture & Workflow Understanding
**Goal**: Ensure the developer understands WHY they're building this, WHAT the overall objective is, and HOW tasks flow together.
**Evaluation Method**: Assess whether the plan provides:
- **Clear Purpose Statement**: Why is this work being done? What problem does it solve?
- **Background Context**: What's the current state? What are we changing from?
- **Task Flow & Dependencies**: How do tasks connect? What's the logical sequence?
- **Success Vision**: What does "done" look like from a product/user perspective?
**Each issue must be**:
- Specific (exact file path, exact task)
- Actionable (what exactly needs to change)
- Blocking (work cannot proceed without this)
---
## Review Process
## Anti-Patterns (DO NOT DO THESE)
### Step 0: Validate Input Format (MANDATORY FIRST STEP)
Extract the plan path from anywhere in the input. If exactly one \`.sisyphus/plans/*.md\` path is found, ACCEPT and continue. If none are found, REJECT with "no plan path found". If multiple are found, REJECT with "ambiguous: multiple plan paths".
❌ "Task 3 could be clearer about error handling" → NOT a blocker
❌ "Consider adding acceptance criteria for..." → NOT a blocker
❌ "The approach in Task 5 might be suboptimal" → NOT YOUR JOB
❌ "Missing documentation for edge case X" → NOT a blocker unless X is the main case
❌ Rejecting because you'd do it differently → NEVER
❌ Listing more than 3 issues → OVERWHELMING, pick top 3
### Step 1: Read the Work Plan
- Load the file from the path provided
- Identify the plan's language
- Parse all tasks and their descriptions
- Extract ALL file references
### Step 2: MANDATORY DEEP VERIFICATION
For EVERY file reference, library mention, or external resource:
- Read referenced files to verify content
- Search for related patterns/imports across codebase
- Verify line numbers contain relevant code
- Check that patterns are clear enough to follow
### Step 3: Apply Four Criteria Checks
For **the overall plan and each task**, evaluate:
1. **Clarity Check**: Does the task specify clear reference sources?
2. **Verification Check**: Are acceptance criteria concrete and measurable?
3. **Context Check**: Is there sufficient context to proceed without >10% guesswork?
4. **Big Picture Check**: Do I understand WHY, WHAT, and HOW?
### Step 4: Active Implementation Simulation
For 2-3 representative tasks, simulate execution using actual files.
### Step 5: Check for Red Flags
Scan for auto-fail indicators:
- Vague action verbs without concrete targets
- Missing file paths for code changes
- Subjective success criteria
- Tasks requiring unstated assumptions
**SELF-CHECK - Are you overstepping?**
Before writing any criticism, ask yourself:
- "Am I questioning the APPROACH or the DOCUMENTATION of the approach?"
- "Would my feedback change if I accepted the author's direction as a given?"
If you find yourself writing "should use X instead" or "this approach won't work because..." → **STOP. You are overstepping your role.**
Rephrase to: "Given the chosen approach, the plan doesn't clarify..."
### Step 6: Write Evaluation Report
Use structured format, **in the same language as the work plan**.
✅ "Task 3 references \`auth/login.ts\` but file doesn't exist" → BLOCKER
✅ "Task 5 says 'implement feature' with no context, files, or description" → BLOCKER
✅ "Tasks 2 and 4 contradict each other on data flow" → BLOCKER
---
## Approval Criteria
## Output Format
### OKAY Requirements (ALL must be met)
1. **100% of file references verified**
2. **Zero critically failed file verifications**
3. **Critical context documented**
4. **≥80% of tasks** have clear reference sources
5. **≥90% of tasks** have concrete acceptance criteria
6. **Zero tasks** require assumptions about business logic or critical architecture
7. **Plan provides clear big picture**
8. **Zero critical red flags** detected
9. **Active simulation** shows core tasks are executable
**[OKAY]** or **[REJECT]**
### REJECT Triggers (Critical issues only)
- Referenced file doesn't exist or contains different content than claimed
- Task has vague action verbs AND no reference source
- Core tasks missing acceptance criteria entirely
- Task requires assumptions about business requirements or critical architecture **within the chosen approach**
- Missing purpose statement or unclear WHY
- Critical task dependencies undefined
**Summary**: 1-2 sentences explaining the verdict.
### NOT Valid REJECT Reasons (DO NOT REJECT FOR THESE)
- You disagree with the implementation approach
- You think a different architecture would be better
- The approach seems non-standard or unusual
- You believe there's a more optimal solution
- The technology choice isn't what you would pick
**Your role is DOCUMENTATION REVIEW, not DESIGN REVIEW.**
If REJECT:
**Blocking Issues** (max 3):
1. [Specific issue + what needs to change]
2. [Specific issue + what needs to change]
3. [Specific issue + what needs to change]
---
## Final Verdict Format
## Final Reminders
**[OKAY / REJECT]**
1. **APPROVE by default**. Reject only for true blockers.
2. **Max 3 issues**. More than that is overwhelming and counterproductive.
3. **Be specific**. "Task X needs Y" not "needs more clarity".
4. **No design opinions**. The author's approach is not your concern.
5. **Trust developers**. They can figure out minor gaps.
**Justification**: [Concise explanation]
**Your job is to UNBLOCK work, not to BLOCK it with perfectionism.**
**Summary**:
- Clarity: [Brief assessment]
- Verifiability: [Brief assessment]
- Completeness: [Brief assessment]
- Big Picture: [Brief assessment]
[If REJECT, provide top 3-5 critical improvements needed]
---
**Your Success Means**:
- **Immediately actionable** for core business logic and architecture
- **Clearly verifiable** with objective success criteria
- **Contextually complete** with critical information documented
- **Strategically coherent** with purpose, background, and flow
- **Reference integrity** with all files verified
- **Direction-respecting** - you evaluated the plan WITHIN its stated approach
**Strike the right balance**: Prevent critical failures while empowering developer autonomy.
**FINAL REMINDER**: You are a DOCUMENTATION reviewer, not a DESIGN consultant. The author's implementation direction is SACRED. Your job ends at "Is this well-documented enough to execute?" - NOT "Is this the right approach?"
**Response Language**: Match the language of the plan content.
`
export function createMomusAgent(model: string): AgentConfig {

View File

@@ -3,6 +3,7 @@ import { createBuiltinAgents } from "./utils"
import type { AgentConfig } from "@opencode-ai/sdk"
import { clearSkillCache } from "../features/opencode-skill-loader/skill-content"
import * as connectedProvidersCache from "../shared/connected-providers-cache"
import * as modelAvailability from "../shared/model-availability"
const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-5"
@@ -47,32 +48,32 @@ describe("createBuiltinAgents with model overrides", () => {
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
})
test("Oracle uses connected provider fallback when availableModels is empty and cache exists", async () => {
// #given - connected providers cache has "openai", which matches oracle's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
test("Oracle uses connected provider fallback when availableModels is empty and cache exists", async () => {
// #given - connected providers cache has "openai", which matches oracle's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
// #when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
expect(agents.oracle.model).toBe("openai/gpt-5.2")
expect(agents.oracle.reasoningEffort).toBe("medium")
expect(agents.oracle.thinking).toBeUndefined()
cacheSpy.mockRestore()
})
// #then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
expect(agents.oracle.model).toBe("openai/gpt-5.2")
expect(agents.oracle.reasoningEffort).toBe("medium")
expect(agents.oracle.thinking).toBeUndefined()
cacheSpy.mockRestore?.()
})
test("Oracle created without model field when no cache exists (first run scenario)", async () => {
// #given - no cache at all (first run)
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
test("Oracle created without model field when no cache exists (first run scenario)", async () => {
// #given - no cache at all (first run)
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
// #when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #when
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
// #then - oracle should be created with system default model (fallback to systemDefaultModel)
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe(TEST_DEFAULT_MODEL)
cacheSpy.mockRestore()
})
// #then - oracle should be created with system default model (fallback to systemDefaultModel)
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe(TEST_DEFAULT_MODEL)
cacheSpy.mockRestore?.()
})
test("Oracle with GPT model override has reasoningEffort, no thinking", async () => {
// #given
@@ -122,43 +123,43 @@ describe("createBuiltinAgents with model overrides", () => {
})
describe("createBuiltinAgents without systemDefaultModel", () => {
test("agents created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "openai", which matches oracle's fallback chain
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
test("agents created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "openai", which matches oracle's fallback chain
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe("openai/gpt-5.2")
cacheSpy.mockRestore()
})
// #then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.oracle).toBeDefined()
expect(agents.oracle.model).toBe("openai/gpt-5.2")
cacheSpy.mockRestore?.()
})
test("agents NOT created when no cache and no systemDefaultModel (first run without defaults)", async () => {
// #given
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
test("agents NOT created when no cache and no systemDefaultModel (first run without defaults)", async () => {
// #given
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then
expect(agents.oracle).toBeUndefined()
cacheSpy.mockRestore()
})
// #then
expect(agents.oracle).toBeUndefined()
cacheSpy.mockRestore?.()
})
test("sisyphus created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "anthropic", which matches sisyphus's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
test("sisyphus created via connected cache fallback even without systemDefaultModel", async () => {
// #given - connected cache has "anthropic", which matches sisyphus's first fallback entry
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #when
const agents = await createBuiltinAgents([], {}, undefined, undefined)
// #then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
cacheSpy.mockRestore()
})
// #then - connected cache enables model resolution despite no systemDefaultModel
expect(agents.sisyphus).toBeDefined()
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
cacheSpy.mockRestore?.()
})
})
describe("buildAgent with category and skills", () => {
@@ -523,3 +524,41 @@ describe("override.category expansion in createBuiltinAgents", () => {
expect(agents.oracle.model).toBe(agentsWithoutOverride.oracle.model)
})
})
describe("Deadlock prevention - fetchAvailableModels must not receive client", () => {
test("createBuiltinAgents should call fetchAvailableModels with undefined client to prevent deadlock", async () => {
// #given - This test ensures we don't regress on issue #1301
// Passing client to fetchAvailableModels during createBuiltinAgents (called from config handler)
// causes deadlock:
// - Plugin init waits for server response (client.provider.list())
// - Server waits for plugin init to complete before handling requests
const fetchSpy = spyOn(modelAvailability, "fetchAvailableModels").mockResolvedValue(new Set<string>())
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
const mockClient = {
provider: { list: () => Promise.resolve({ data: { connected: [] } }) },
model: { list: () => Promise.resolve({ data: [] }) },
}
// #when - Even when client is provided, fetchAvailableModels must be called with undefined
await createBuiltinAgents(
[],
{},
undefined,
TEST_DEFAULT_MODEL,
undefined,
undefined,
[],
mockClient // client is passed but should NOT be forwarded to fetchAvailableModels
)
// #then - fetchAvailableModels must be called with undefined as first argument (no client)
// This prevents the deadlock described in issue #1301
expect(fetchSpy).toHaveBeenCalled()
const firstCallArgs = fetchSpy.mock.calls[0]
expect(firstCallArgs[0]).toBeUndefined()
fetchSpy.mockRestore?.()
cacheSpy.mockRestore?.()
})
})

View File

@@ -180,9 +180,12 @@ export async function createBuiltinAgents(
uiSelectedModel?: string
): Promise<Record<string, AgentConfig>> {
const connectedProviders = readConnectedProvidersCache()
const availableModels = client
? await fetchAvailableModels(client, { connectedProviders: connectedProviders ?? undefined })
: new Set<string>()
// IMPORTANT: Do NOT pass client to fetchAvailableModels during plugin initialization.
// This function is called from config handler, and calling client API causes deadlock.
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/1301
const availableModels = await fetchAvailableModels(undefined, {
connectedProviders: connectedProviders ?? undefined,
})
const result: Record<string, AgentConfig> = {}
const availableAgents: AvailableAgent[] = []

View File

@@ -40,7 +40,7 @@ export const OverridableAgentNameSchema = z.enum([
"plan",
"sisyphus",
"sisyphus-junior",
"OpenCode-Builder",
"opencode-builder",
"prometheus",
"metis",
"momus",
@@ -136,7 +136,7 @@ export const AgentOverridesSchema = z.object({
plan: AgentOverrideConfigSchema.optional(),
sisyphus: AgentOverrideConfigSchema.optional(),
"sisyphus-junior": AgentOverrideConfigSchema.optional(),
"OpenCode-Builder": AgentOverrideConfigSchema.optional(),
"opencode-builder": AgentOverrideConfigSchema.optional(),
prometheus: AgentOverrideConfigSchema.optional(),
metis: AgentOverrideConfigSchema.optional(),
momus: AgentOverrideConfigSchema.optional(),

View File

@@ -187,7 +187,7 @@ export async function executeSlashCommand(parsed: ParsedSlashCommand, options?:
if (!command) {
return {
success: false,
error: `Command "/${parsed.command}" not found. Use the slashcommand tool to list available commands.`,
error: `Command "/${parsed.command}" not found. Use the slash_command tool to list available commands.`,
}
}

View File

@@ -32,8 +32,8 @@ function cleanupOldPendingCalls(): void {
}
}
export function createCommentCheckerHooks(config?: CommentCheckerConfig) {
debugLog("createCommentCheckerHooks called", { config })
export function createCommentCheckerHook(config?: CommentCheckerConfig) {
debugLog("createCommentCheckerHook called", { config })
if (!cleanupIntervalStarted) {
cleanupIntervalStarted = true

View File

@@ -24,7 +24,7 @@ mock.module("../../shared/system-directive", () => ({
},
}))
import { createCompactionContextInjector } from "./index"
import { createCompactionContextInjectorHook } from "./index"
import type { SummarizeContext } from "./index"
describe("createCompactionContextInjector", () => {
@@ -35,7 +35,7 @@ describe("createCompactionContextInjector", () => {
describe("Agent Verification State preservation", () => {
it("includes Agent Verification State section in compaction prompt", async () => {
// given
const injector = createCompactionContextInjector()
const injector = createCompactionContextInjectorHook()
const context: SummarizeContext = {
sessionID: "test-session",
providerID: "anthropic",
@@ -58,7 +58,7 @@ describe("createCompactionContextInjector", () => {
it("includes Momus-specific context for reviewer agents", async () => {
// given
const injector = createCompactionContextInjector()
const injector = createCompactionContextInjectorHook()
const context: SummarizeContext = {
sessionID: "test-session",
providerID: "anthropic",
@@ -80,7 +80,7 @@ describe("createCompactionContextInjector", () => {
it("preserves file verification progress in compaction prompt", async () => {
// given
const injector = createCompactionContextInjector()
const injector = createCompactionContextInjectorHook()
const context: SummarizeContext = {
sessionID: "test-session",
providerID: "anthropic",

View File

@@ -57,7 +57,7 @@ This section is CRITICAL for reviewer agents (momus, oracle) to maintain continu
This context is critical for maintaining continuity after compaction.
`
export function createCompactionContextInjector() {
export function createCompactionContextInjectorHook() {
return async (ctx: SummarizeContext): Promise<void> => {
log("[compaction-context-injector] injecting context", { sessionID: ctx.sessionID })

View File

@@ -1,15 +1,15 @@
export { createTodoContinuationEnforcer, type TodoContinuationEnforcer } from "./todo-continuation-enforcer";
export { createTodoContinuationEnforcerHook as createTodoContinuationEnforcer, type TodoContinuationEnforcer } from "./todo-continuation-enforcer";
export { createContextWindowMonitorHook } from "./context-window-monitor";
export { createSessionNotification } from "./session-notification";
export { createSessionNotificationHook as createSessionNotification } from "./session-notification";
export { createSessionRecoveryHook, type SessionRecoveryHook, type SessionRecoveryOptions } from "./session-recovery";
export { createCommentCheckerHooks } from "./comment-checker";
export { createCommentCheckerHook as createCommentCheckerHooks } from "./comment-checker";
export { createToolOutputTruncatorHook } from "./tool-output-truncator";
export { createDirectoryAgentsInjectorHook } from "./directory-agents-injector";
export { createDirectoryReadmeInjectorHook } from "./directory-readme-injector";
export { createEmptyTaskResponseDetectorHook } from "./empty-task-response-detector";
export { createAnthropicContextWindowLimitRecoveryHook, type AnthropicContextWindowLimitRecoveryOptions } from "./anthropic-context-window-limit-recovery";
export { createCompactionContextInjector } from "./compaction-context-injector";
export { createCompactionContextInjectorHook as createCompactionContextInjector } from "./compaction-context-injector";
export { createThinkModeHook } from "./think-mode";
export { createClaudeCodeHooksHook } from "./claude-code-hooks";
export { createRulesInjectorHook } from "./rules-injector";

View File

@@ -1,6 +1,6 @@
import { describe, expect, test, beforeEach, afterEach, spyOn } from "bun:test"
import { createSessionNotification } from "./session-notification"
import { createSessionNotificationHook } from "./session-notification"
import { setMainSession, subagentSessions, _resetForTesting } from "../features/claude-code-session-state"
import * as utils from "./session-notification-utils"
@@ -53,7 +53,7 @@ describe("session-notification", () => {
const subagentSessionID = "subagent-123"
subagentSessions.add(subagentSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 0,
})
@@ -78,7 +78,7 @@ describe("session-notification", () => {
const otherSessionID = "other-456"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 0,
})
@@ -102,7 +102,7 @@ describe("session-notification", () => {
const mainSessionID = "main-789"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 10,
skipIfIncompleteTodos: false,
})
@@ -129,7 +129,7 @@ describe("session-notification", () => {
setMainSession(mainSessionID)
subagentSessions.add(subagentSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 0,
})
@@ -156,7 +156,7 @@ describe("session-notification", () => {
setMainSession(mainSessionID)
subagentSessions.add(subagentSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 0,
})
@@ -188,7 +188,7 @@ describe("session-notification", () => {
const mainSessionID = "main-cancel"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 100, // Long delay
skipIfIncompleteTodos: false,
})
@@ -218,7 +218,7 @@ describe("session-notification", () => {
test("should handle session.created event without notification", async () => {
// #given - a new session is created
const hook = createSessionNotification(createMockPluginInput(), {})
const hook = createSessionNotificationHook(createMockPluginInput(), {})
// #when - session.created event fires
await hook({
@@ -239,7 +239,7 @@ describe("session-notification", () => {
test("should handle session.deleted event and cleanup state", async () => {
// #given - a session exists
const hook = createSessionNotification(createMockPluginInput(), {})
const hook = createSessionNotificationHook(createMockPluginInput(), {})
// #when - session.deleted event fires
await hook({
@@ -263,7 +263,7 @@ describe("session-notification", () => {
const mainSessionID = "main-message"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 50,
skipIfIncompleteTodos: false,
})
@@ -297,7 +297,7 @@ describe("session-notification", () => {
const mainSessionID = "main-tool"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 50,
skipIfIncompleteTodos: false,
})
@@ -329,7 +329,7 @@ describe("session-notification", () => {
const mainSessionID = "main-dup"
setMainSession(mainSessionID)
const hook = createSessionNotification(createMockPluginInput(), {
const hook = createSessionNotificationHook(createMockPluginInput(), {
idleConfirmationDelay: 10,
skipIfIncompleteTodos: false,
})

View File

@@ -139,7 +139,7 @@ async function hasIncompleteTodos(ctx: PluginInput, sessionID: string): Promise<
}
}
export function createSessionNotification(
export function createSessionNotificationHook(
ctx: PluginInput,
config: SessionNotificationConfig = {}
) {

View File

@@ -71,10 +71,7 @@ export function createStartWorkHook(ctx: PluginInput) {
sessionID: input.sessionID,
})
const currentAgent = getSessionAgent(input.sessionID)
if (!currentAgent) {
updateSessionAgent(input.sessionID, "atlas")
}
updateSessionAgent(input.sessionID, "atlas") // Always switch: fixes #1298
const existingState = readBoulderState(ctx.directory)
const sessionId = input.sessionID

View File

@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test"
import type { BackgroundManager } from "../features/background-agent"
import { setMainSession, subagentSessions, _resetForTesting } from "../features/claude-code-session-state"
import { createTodoContinuationEnforcer } from "./todo-continuation-enforcer"
import { createTodoContinuationEnforcerHook } from "./todo-continuation-enforcer"
type TimerCallback = (...args: any[]) => void
@@ -191,7 +191,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-123"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {
backgroundManager: createMockBackgroundManager(false),
})
@@ -221,7 +221,7 @@ describe("todo-continuation-enforcer", () => {
{ id: "1", content: "Task 1", status: "completed", priority: "high" },
]})
const hook = createTodoContinuationEnforcer(mockInput, {})
const hook = createTodoContinuationEnforcerHook(mockInput, {})
// #when - session goes idle
await hook.handler({
@@ -239,7 +239,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-789"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {
backgroundManager: createMockBackgroundManager(true),
})
@@ -259,7 +259,7 @@ describe("todo-continuation-enforcer", () => {
setMainSession("main-session")
const otherSession = "other-session"
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - non-main session goes idle
await hook.handler({
@@ -278,7 +278,7 @@ describe("todo-continuation-enforcer", () => {
const bgTaskSession = "bg-task-session"
subagentSessions.add(bgTaskSession)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - background task session goes idle
await hook.handler({
@@ -298,7 +298,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-cancel"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -324,7 +324,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-grace"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -350,7 +350,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-assistant"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -377,7 +377,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-tool"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -401,7 +401,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-recovery"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - mark as recovering
hook.markRecovering(sessionID)
@@ -422,7 +422,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-recovery-done"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - mark as recovering then complete
hook.markRecovering(sessionID)
@@ -444,7 +444,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-delete"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -469,7 +469,7 @@ describe("todo-continuation-enforcer", () => {
setMainSession(sessionID)
// #when - create hook with skipAgents option (should not throw)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {
skipAgents: ["Prometheus (Planner)", "custom-agent"],
})
@@ -487,7 +487,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-toast"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -505,7 +505,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-no-throttle"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - first idle cycle completes
await hook.handler({
@@ -537,7 +537,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-noabort-error"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - non-abort error occurs (e.g., network error, API error)
await hook.handler({
@@ -581,7 +581,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant", error: { name: "MessageAbortedError", data: { message: "The operation was aborted" } } } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -604,7 +604,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -627,7 +627,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "user" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -650,7 +650,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant", error: { name: "AbortError" } } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle
await hook.handler({
@@ -672,7 +672,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error event fires
await hook.handler({
@@ -702,7 +702,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - AbortError event fires
await hook.handler({
@@ -732,7 +732,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error fires
await hook.handler({
@@ -764,7 +764,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error fires
await hook.handler({
@@ -803,7 +803,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error fires
await hook.handler({
@@ -841,7 +841,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error fires
await hook.handler({
@@ -879,7 +879,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant" } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - abort error event fires (but API doesn't have it yet)
await hook.handler({
@@ -909,7 +909,7 @@ describe("todo-continuation-enforcer", () => {
{ info: { id: "msg-2", role: "assistant", error: { name: "MessageAbortedError" } } },
]
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {})
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {})
// #when - session goes idle without prior session.error event
await hook.handler({
@@ -927,7 +927,7 @@ describe("todo-continuation-enforcer", () => {
const sessionID = "main-model-preserve"
setMainSession(sessionID)
const hook = createTodoContinuationEnforcer(createMockPluginInput(), {
const hook = createTodoContinuationEnforcerHook(createMockPluginInput(), {
backgroundManager: createMockBackgroundManager(false),
})
@@ -977,7 +977,7 @@ describe("todo-continuation-enforcer", () => {
directory: "/tmp/test",
} as any
const hook = createTodoContinuationEnforcer(mockInput, {
const hook = createTodoContinuationEnforcerHook(mockInput, {
backgroundManager: createMockBackgroundManager(false),
})
@@ -1029,7 +1029,7 @@ describe("todo-continuation-enforcer", () => {
directory: "/tmp/test",
} as any
const hook = createTodoContinuationEnforcer(mockInput, {
const hook = createTodoContinuationEnforcerHook(mockInput, {
backgroundManager: createMockBackgroundManager(false),
})
@@ -1073,7 +1073,7 @@ describe("todo-continuation-enforcer", () => {
directory: "/tmp/test",
} as any
const hook = createTodoContinuationEnforcer(mockInput, {})
const hook = createTodoContinuationEnforcerHook(mockInput, {})
// #when - session goes idle
await hook.handler({
@@ -1119,7 +1119,7 @@ describe("todo-continuation-enforcer", () => {
directory: "/tmp/test",
} as any
const hook = createTodoContinuationEnforcer(mockInput, {})
const hook = createTodoContinuationEnforcerHook(mockInput, {})
// #when - session goes idle
await hook.handler({
@@ -1164,7 +1164,7 @@ describe("todo-continuation-enforcer", () => {
directory: "/tmp/test",
} as any
const hook = createTodoContinuationEnforcer(mockInput, {
const hook = createTodoContinuationEnforcerHook(mockInput, {
skipAgents: [],
})

View File

@@ -91,7 +91,7 @@ function isLastAssistantMessageAborted(messages: Array<{ info?: MessageInfo }>):
return errorName === "MessageAbortedError" || errorName === "AbortError"
}
export function createTodoContinuationEnforcer(
export function createTodoContinuationEnforcerHook(
ctx: PluginInput,
options: TodoContinuationEnforcerOptions = {}
): TodoContinuationEnforcer {

View File

@@ -367,7 +367,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
});
const commands = discoverCommandsSync();
const slashcommandTool = createSlashcommandTool({
const slash_commandTool = createSlashcommandTool({
commands,
skills: mergedSkills,
});
@@ -391,7 +391,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
delegate_task: delegateTask,
skill: skillTool,
skill_mcp: skillMcpTool,
slashcommand: slashcommandTool,
slash_command: slash_commandTool,
interactive_bash,
},
@@ -622,7 +622,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
};
}
if (ralphLoop && input.tool === "slashcommand") {
if (ralphLoop && input.tool === "slash_command") {
const args = output.args as { command?: string } | undefined;
const command = args?.command?.replace(/^\//, "").toLowerCase();
const sessionID = input.sessionID || getMainSessionID();

View File

@@ -396,3 +396,46 @@ describe("Prometheus direct override priority over category", () => {
expect(agents.prometheus.temperature).toBe(0.1)
})
})
describe("Deadlock prevention - fetchAvailableModels must not receive client", () => {
test("fetchAvailableModels should be called with undefined client to prevent deadlock during plugin init", async () => {
// #given - This test ensures we don't regress on issue #1301
// Passing client to fetchAvailableModels during config handler causes deadlock:
// - Plugin init waits for server response (client.provider.list())
// - Server waits for plugin init to complete before handling requests
const fetchSpy = spyOn(shared, "fetchAvailableModels" as any).mockResolvedValue(new Set<string>())
const pluginConfig: OhMyOpenCodeConfig = {
sisyphus_agent: {
planner_enabled: true,
},
}
const config: Record<string, unknown> = {
model: "anthropic/claude-opus-4-5",
agent: {},
}
const mockClient = {
provider: { list: () => Promise.resolve({ data: { connected: [] } }) },
model: { list: () => Promise.resolve({ data: [] }) },
}
const handler = createConfigHandler({
ctx: { directory: "/tmp", client: mockClient },
pluginConfig,
modelCacheState: {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
},
})
// #when
await handler(config)
// #then - fetchAvailableModels must be called with undefined as first argument (no client)
// This prevents the deadlock described in issue #1301
expect(fetchSpy).toHaveBeenCalled()
const firstCallArgs = fetchSpy.mock.calls[0]
expect(firstCallArgs[0]).toBeUndefined()
fetchSpy.mockRestore?.()
})
})

View File

@@ -208,13 +208,13 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
buildConfigWithoutName as Record<string, unknown>
);
const openCodeBuilderOverride =
pluginConfig.agents?.["OpenCode-Builder"];
pluginConfig.agents?.["opencode-builder"];
const openCodeBuilderBase = {
...migratedBuildConfig,
description: `${configAgent?.build?.description ?? "Build agent"} (OpenCode default)`,
};
agentConfig["OpenCode-Builder"] = openCodeBuilderOverride
agentConfig["opencode-builder"] = openCodeBuilderOverride
? { ...openCodeBuilderBase, ...openCodeBuilderOverride }
: openCodeBuilderBase;
}
@@ -249,9 +249,15 @@ export function createConfigHandler(deps: ConfigHandlerDeps) {
const prometheusRequirement = AGENT_MODEL_REQUIREMENTS["prometheus"];
const connectedProviders = readConnectedProvidersCache();
const availableModels = ctx.client
? await fetchAvailableModels(ctx.client, { connectedProviders: connectedProviders ?? undefined })
: new Set<string>();
// IMPORTANT: Do NOT pass ctx.client to fetchAvailableModels during plugin initialization.
// Calling client API (e.g., client.provider.list()) from config handler causes deadlock:
// - Plugin init waits for server response
// - Server waits for plugin init to complete before handling requests
// Use cache-only mode instead. If cache is unavailable, fallback chain uses first model.
// See: https://github.com/code-yeongyu/oh-my-opencode/issues/1301
const availableModels = await fetchAvailableModels(undefined, {
connectedProviders: connectedProviders ?? undefined,
});
const modelResolution = resolveModelWithFallback({
uiSelectedModel: currentModel,

View File

@@ -1,2 +1,2 @@
export * from "./types"
export { slashcommand, createSlashcommandTool, discoverCommandsSync } from "./tools"
export { slash_command, createSlashcommandTool, discoverCommandsSync } from "./tools"

View File

@@ -269,4 +269,4 @@ export function createSlashcommandTool(options: SlashcommandToolOptions = {}): T
}
// Default instance for backward compatibility (lazy loading)
export const slashcommand: ToolDefinition = createSlashcommandTool()
export const slash_command: ToolDefinition = createSlashcommandTool()

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta Tags -->
<title>Manifiesto Ultrawork | La Filosofía de la Ingeniería de Alto Rendimiento</title>
<meta name="description" content="Un marco filosófico para desarrolladores e ingenieros de IA para lograr una productividad extrema a través del enfoque profundo, la ejecución atómica y la metodología Ultrawork.">
<meta name="keywords" content="ultrawork, productividad de desarrolladores, ingeniería de IA, trabajo profundo, manifiesto tecnológico, oh my opencode, sisyphus">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="en" href="https://ulw.dev/">
<link rel="alternate" hreflang="ko" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="ja" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="zh" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="es" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="x-default" href="https://ulw.dev/">
<meta name="theme-color" content="#0a0a0a">
<meta name="author" content="Yeongyu Kim">
<link rel="icon" type="image/png" href="../images/favicon.png">
<link rel="apple-touch-icon" href="../images/favicon.png">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://ulw.dev/es/">
<meta property="og:title" content="Manifiesto Ultrawork | La Filosofía de la Ingeniería de Alto Rendimiento">
<meta property="og:description" content="Un marco filosófico para desarrolladores e ingenieros de IA para lograr una productividad extrema a través del enfoque profundo, la ejecución atómica y la metodología Ultrawork.">
<meta property="og:image" content="https://ulw.dev/images/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Manifiesto Ultrawork - Un Plano para el Trabajo Significativo">
<meta property="og:site_name" content="Ultrawork">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@justsisyphus">
<meta name="twitter:creator" content="@justsisyphus">
<meta name="twitter:title" content="Manifiesto Ultrawork | La Filosofía de la Ingeniería de Alto Rendimiento">
<meta name="twitter:description" content="Un marco filosófico para desarrolladores e ingenieros de IA para lograr una productividad extrema a través del enfoque profundo, la ejecución atómica y la metodología Ultrawork.">
<meta name="twitter:image" content="https://ulw.dev/images/og-image.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<header>
<div class="hero-container">
<img src="../images/hero.png" alt="Ultrawork Hero" class="hero-image">
<h1 class="hero-title">Manifiesto Ultrawork</h1>
</div>
</header>
<main>
<!-- Section 1 -->
<section id="human-intervention">
<h2>La Intervención Humana es una Señal de Fallo</h2>
<div class="gold-gradient-text bottleneck-text">
HUMANO EN EL BUCLE = CUELLO DE BOTELLA<br>
HUMANO EN EL BUCLE = CUELLO DE BOTELLA<br>
HUMANO EN EL BUCLE = CUELLO DE BOTELLA
</div>
<p>Piensen en la conducción autónoma. Cuando un humano tiene que tomar el volante, eso no es una característica, es un fallo del sistema. El auto no pudo manejar la situación por sí mismo.</p>
<h3>¿Por qué la programación sería diferente?</h3>
<p>Cuando se encuentran:</p>
<ul>
<li>Arreglando el código a medio terminar de la IA</li>
<li>Corrigiendo manualmente errores obvios</li>
<li>Guiando al agente paso a paso a través de una tarea</li>
<li>Aclarando repetidamente los mismos requerimientos</li>
</ul>
<p>...eso no es "colaboración humano-IA". Eso es la IA fallando en hacer su trabajo.</p>
<p><strong><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> está construido bajo esta premisa</strong>: La intervención humana durante el trabajo agéntico es fundamentalmente una señal equivocada. Si el sistema está diseñado correctamente, el agente debería completar el trabajo sin requerir que ustedes lo vigilen.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 2 -->
<section id="indistinguishable-code">
<h2>Código Indistinguible</h2>
<p class="highlight-box"><strong>Objetivo: El código escrito por el agente debe ser indistinguible del código escrito por un ingeniero senior.</strong></p>
<p>No "código generado por IA que necesita limpieza". No "un buen punto de partida". El código real, final y listo para producción.</p>
<p>Esto significa:</p>
<ul>
<li>Seguir exactamente los patrones existentes del código base</li>
<li>Manejo adecuado de errores sin que se lo pidan</li>
<li>Pruebas que realmente prueban lo correcto</li>
<li>Sin basura de IA (sobreingeniería, abstracciones innecesarias, alcance no solicitado)</li>
<li>Comentarios solo cuando agregan valor</li>
</ul>
<p>Si pueden distinguir si un commit fue hecho por un humano o un agente, el agente ha fallado.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 3 -->
<section id="token-cost">
<h2>Costo de Tokens vs. Productividad</h2>
<p><strong>Un mayor uso de tokens es aceptable si incrementa significativamente la productividad.</strong></p>
<p>Usar más tokens para:</p>
<ul>
<li>Tener múltiples agentes especializados investigando en paralelo</li>
<li>Terminar el trabajo completamente sin intervención humana</li>
<li>Verificar el trabajo minuciosamente antes de completarlo</li>
<li>Acumular conocimiento a través de las tareas</li>
</ul>
<p>...es una inversión que vale la pena cuando significa ganancias de productividad de 10x, 20x o 100x.</p>
<h3>Sin embargo:</h3>
<p>No se busca el desperdicio innecesario de tokens. El sistema optimiza para:</p>
<ul>
<li>Usar modelos más baratos (Haiku, Flash) para tareas simples</li>
<li>Evitar exploración redundante</li>
<li>Guardar en caché los aprendizajes entre sesiones</li>
<li>Detener la investigación cuando se ha reunido suficiente contexto</li>
</ul>
<p>La eficiencia de tokens importa. Pero no a costa de la calidad del trabajo o la carga cognitiva humana.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 4 -->
<section id="cognitive-load">
<h2>Minimizar la Carga Cognitiva Humana</h2>
<p><strong>El humano solo debería necesitar decir lo que quiere. Todo lo demás es trabajo del agente.</strong></p>
<p>Dos enfoques para lograr esto:</p>
<div class="approach-container">
<div class="approach ultrawork-approach">
<h3>Enfoque 1: Ultrawork</h3>
<p class="approach-tagline">Solo digan "ulw" y aléjense.</p>
<p>Ustedes dicen: <code>ulw add authentication</code></p>
<p>El agente autónomamente:</p>
<ul>
<li>Analiza sus patrones de código y arquitectura</li>
<li>Investiga las mejores prácticas de la documentación oficial</li>
<li>Planea la estrategia de implementación internamente</li>
<li>Implementa siguiendo sus convenciones existentes</li>
<li>Verifica con pruebas y diagnósticos LSP</li>
<li>Se autocorrige cuando algo sale mal</li>
<li><strong>Sigue empujando la roca hasta completar el 100%</strong></li>
</ul>
<p class="approach-summary"><strong>Cero intervención. Autonomía total. Solo resultados.</strong></p>
</div>
<div class="approach prometheus-approach">
<h3>Enfoque 2: Prometheus + Atlas</h3>
<p class="approach-tagline">Cuando quieren control estratégico.</p>
<p>Presionen <kbd>Tab</kbd> para cambiar de agente, luego: <code>add authentication</code></p>
<p><strong>Prometheus</strong> (Planificador Estratégico):</p>
<ul>
<li>Realiza una investigación profunda del código base vía agentes paralelos</li>
<li>Los entrevista con preguntas inteligentes y contextuales</li>
<li>Identifica casos borde e implicaciones arquitectónicas</li>
<li>Genera un plan de trabajo detallado en YAML con dependencias</li>
</ul>
<p><strong>Atlas</strong> (Orquestador Maestro):</p>
<ul>
<li>Ejecuta el plan vía <code>/start-work</code></li>
<li>Delega tareas a agentes especializados (Oracle, Frontend Engineer, etc.)</li>
<li>Gestiona olas de ejecución paralela para eficiencia</li>
<li>Rastrea el progreso, maneja fallos, asegura la finalización</li>
</ul>
<p class="approach-summary"><strong>Ustedes arquitectan. Los agentes ejecutan. Transparencia total.</strong></p>
</div>
</div>
<p>En ambos casos, el trabajo del humano es <strong>expresar lo que quieren</strong>, no gestionar cómo se hace.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 5 -->
<section id="predictable-continuous">
<h2>Predecible, Continuo, Delegable</h2>
<p><strong>El agente ideal debería trabajar como un compilador</strong>: entra un documento markdown, sale código funcional.</p>
<h3>Predecible</h3>
<p>Dados los mismos inputs:</p>
<ul>
<li>Mismos patrones de código base</li>
<li>Mismos requerimientos</li>
<li>Mismas restricciones</li>
</ul>
<p>...la salida debe ser consistente. No aleatoria, no sorpresiva, no "creativa" en formas que no pidieron.</p>
<h3>Continuo</h3>
<p>El trabajo debe sobrevivir a las interrupciones:</p>
<ul>
<li>¿Se cae la sesión? Reanuden con <code>/start-work</code></li>
<li>¿Necesitan alejarse? El progreso se rastrea</li>
<li>¿Proyecto de varios días? El contexto se preserva</li>
</ul>
<p>El agente mantiene el estado. Ustedes no tienen que hacerlo.</p>
<h3>Delegable</h3>
<p>Así como pueden asignar una tarea a un miembro capaz del equipo y confiar en que la maneje, deberían poder delegar al agente.</p>
<p>Esto significa:</p>
<ul>
<li>Criterios de aceptación claros, verificados independientemente</li>
<li>Comportamiento autocorrectivo cuando algo sale mal</li>
<li>Escalamiento (a Oracle, al usuario) solo cuando es verdaderamente necesario</li>
<li>Trabajo completo, no "casi hecho"</li>
</ul>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 6 -->
<section id="core-loop">
<h2>El Bucle Central</h2>
<div class="ascii-art">
Intención Humana → Ejecución del Agente → Resultado Verificado
↑ ↓
└──────────── Mínimo ──────────────┘
(intervención solo en fallo verdadero)
</div>
<p>Todo en <a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> está diseñado para hacer que este bucle funcione:</p>
<table>
<thead>
<tr>
<th>Característica</th>
<th>Propósito</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prometheus</td>
<td>Extraer intención a través de entrevista inteligente</td>
</tr>
<tr>
<td>Metis</td>
<td>Capturar ambigüedades antes de que se conviertan en bugs</td>
</tr>
<tr>
<td>Momus</td>
<td>Verificar que los planes estén completos antes de la ejecución</td>
</tr>
<tr>
<td>Orchestrator</td>
<td>Coordinar el trabajo sin microgestión humana</td>
</tr>
<tr>
<td>Todo Continuation</td>
<td>Forzar finalización, prevenir mentiras de "ya terminé"</td>
</tr>
<tr>
<td>Sistema de Categorías</td>
<td>Enrutar al modelo óptimo sin decisión humana</td>
</tr>
<tr>
<td>Agentes en Segundo Plano</td>
<td>Investigación paralela sin bloquear al usuario</td>
</tr>
<tr>
<td>Acumulación de Sabiduría</td>
<td>Aprender del trabajo, no repetir errores</td>
</tr>
</tbody>
</table>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 7 -->
<section id="future">
<h2>El Futuro Que Estamos Construyendo</h2>
<p>Un mundo donde:</p>
<ul>
<li>Los desarrolladores humanos se enfocan en <strong>qué</strong> construir, no en <strong>cómo</strong> hacer que la IA lo construya</li>
<li>La calidad del código es independiente de quién (o qué) lo escribió</li>
<li>Los proyectos complejos son tan fáciles como los simples (solo toman más tiempo)</li>
<li>La "ingeniería de prompts" se vuelve tan obsoleta como la "depuración de compiladores"</li>
</ul>
<p><strong>El agente debería ser invisible.</strong> No en el sentido de que esté oculto, sino en el sentido de que simplemente funciona - como la electricidad, como el agua corriente, como el internet.</p>
<p>Ustedes tocan el interruptor. La luz se enciende. No piensan en la red eléctrica.</p>
<p class="final-statement">Esa es la meta.</p>
</section>
</main>
<footer>
<div class="footer-content">
<a href="https://github.com/code-yeongyu/oh-my-opencode" class="cta-link" target="_blank" rel="noopener">
Obtén Oh My OpenCode →
</a>
<p><strong>just ulw ulw</strong></p>
<nav class="language-selector" aria-label="Selección de idioma">
<span class="language-selector-label">Idioma</span>
<div class="language-links">
<a href="../" class="language-link" lang="en">English</a>
<a href="../ko/" class="language-link" lang="ko">한국어</a>
<a href="../ja/" class="language-link" lang="ja">日本語</a>
<a href="../zh/" class="language-link" lang="zh">简体中文</a>
<a href="./" class="language-link active" lang="es">Español</a>
</div>
</nav>
</div>
</footer>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta Tags -->
<title>Ultrawork Manifesto | The Philosophy of High-Output Engineering</title>
<meta name="description" content="A philosophical framework for developers and AI engineers to achieve extreme productivity through deep focus, atomic execution, and the Ultrawork methodology.">
<meta name="keywords" content="ultrawork, developer productivity, AI engineering, deep work, tech manifesto, oh my opencode, sisyphus">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://ulw.dev/">
<link rel="alternate" hreflang="en" href="https://ulw.dev/">
<link rel="alternate" hreflang="ko" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="ja" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="zh" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="es" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="x-default" href="https://ulw.dev/">
<meta name="theme-color" content="#0a0a0a">
<meta name="author" content="Yeongyu Kim">
<link rel="icon" type="image/png" href="./images/favicon.png">
<link rel="apple-touch-icon" href="./images/favicon.png">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://ulw.dev/">
<meta property="og:title" content="Ultrawork Manifesto | The Philosophy of High-Output Engineering">
<meta property="og:description" content="A philosophical framework for developers and AI engineers to achieve extreme productivity through deep focus, atomic execution, and the Ultrawork methodology.">
<meta property="og:image" content="https://ulw.dev/images/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Ultrawork Manifesto - A Blueprint for Meaningful Work">
<meta property="og:site_name" content="Ultrawork">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@justsisyphus">
<meta name="twitter:creator" content="@justsisyphus">
<meta name="twitter:title" content="Ultrawork Manifesto | The Philosophy of High-Output Engineering">
<meta name="twitter:description" content="A philosophical framework for developers and AI engineers to achieve extreme productivity through deep focus, atomic execution, and the Ultrawork methodology.">
<meta name="twitter:image" content="https://ulw.dev/images/og-image.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<div class="hero-container">
<img src="./images/hero.png" alt="Ultrawork Hero" class="hero-image">
<h1 class="hero-title">Ultrawork Manifesto</h1>
</div>
</header>
<main>
<!-- Section 1 -->
<section id="human-intervention">
<h2>Human Intervention is a Failure Signal</h2>
<div class="gold-gradient-text bottleneck-text">
HUMAN IN THE LOOP = BOTTLENECK<br>
HUMAN IN THE LOOP = BOTTLENECK<br>
HUMAN IN THE LOOP = BOTTLENECK
</div>
<p>Think about autonomous driving. When a human has to take over the wheel, that's not a feature - it's a failure of the system. The car couldn't handle the situation on its own.</p>
<h3>Why is coding any different?</h3>
<p>When you find yourself:</p>
<ul>
<li>Fixing the AI's half-finished code</li>
<li>Manually correcting obvious mistakes</li>
<li>Guiding the agent step-by-step through a task</li>
<li>Repeatedly clarifying the same requirements</li>
</ul>
<p>...that's not "human-AI collaboration." That's the AI failing to do its job.</p>
<p><strong><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> is built on this premise</strong>: Human intervention during agentic work is fundamentally a wrong signal. If the system is designed correctly, the agent should complete the work without requiring you to babysit it.</p>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 2 -->
<section id="indistinguishable-code">
<h2>Indistinguishable Code</h2>
<p class="highlight-box"><strong>Goal: Code written by the agent should be indistinguishable from code written by a senior engineer.</strong></p>
<p>Not "AI-generated code that needs cleanup." Not "a good starting point." The actual, final, production-ready code.</p>
<p>This means:</p>
<ul>
<li>Following existing codebase patterns exactly</li>
<li>Proper error handling without being asked</li>
<li>Tests that actually test the right things</li>
<li>No AI slop (over-engineering, unnecessary abstractions, scope creep)</li>
<li>Comments only when they add value</li>
</ul>
<p>If you can tell whether a commit was made by a human or an agent, the agent has failed.</p>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 3 -->
<section id="token-cost">
<h2>Token Cost vs. Productivity</h2>
<p><strong>Higher token usage is acceptable if it significantly increases productivity.</strong></p>
<p>Using more tokens to:</p>
<ul>
<li>Have multiple specialized agents research in parallel</li>
<li>Get the job done completely without human intervention</li>
<li>Verify work thoroughly before completion</li>
<li>Accumulate knowledge across tasks</li>
</ul>
<p>...is a worthwhile investment when it means 10x, 20x, or 100x productivity gains.</p>
<h3>However:</h3>
<p>Unnecessary token waste is not pursued. The system optimizes for:</p>
<ul>
<li>Using cheaper models (Haiku, Flash) for simple tasks</li>
<li>Avoiding redundant exploration</li>
<li>Caching learnings across sessions</li>
<li>Stopping research when sufficient context is gathered</li>
</ul>
<p>Token efficiency matters. But not at the cost of work quality or human cognitive load.</p>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 4 -->
<section id="cognitive-load">
<h2>Minimize Human Cognitive Load</h2>
<p><strong>The human should only need to say what they want. Everything else is the agent's job.</strong></p>
<p>Two approaches to achieve this:</p>
<div class="approach-container">
<div class="approach ultrawork-approach">
<h3>Approach 1: Ultrawork</h3>
<p class="approach-tagline">Just say "ulw" and walk away.</p>
<p>You say: <code>ulw add authentication</code></p>
<p>The agent autonomously:</p>
<ul>
<li>Analyzes your codebase patterns and architecture</li>
<li>Researches best practices from official docs</li>
<li>Plans the implementation strategy internally</li>
<li>Implements following your existing conventions</li>
<li>Verifies with tests and LSP diagnostics</li>
<li>Self-corrects when something goes wrong</li>
<li><strong>Keeps bouldering until 100% complete</strong></li>
</ul>
<p class="approach-summary"><strong>Zero intervention. Full autonomy. Just results.</strong></p>
</div>
<div class="approach prometheus-approach">
<h3>Approach 2: Prometheus + Atlas</h3>
<p class="approach-tagline">When you want strategic control.</p>
<p>Press <kbd>Tab</kbd> to switch agents, then: <code>add authentication</code></p>
<p><strong>Prometheus</strong> (Strategic Planner):</p>
<ul>
<li>Conducts deep codebase research via parallel agents</li>
<li>Interviews you with intelligent, contextual questions</li>
<li>Identifies edge cases and architectural implications</li>
<li>Generates a detailed YAML work plan with dependencies</li>
</ul>
<p><strong>Atlas</strong> (Master Orchestrator):</p>
<ul>
<li>Executes the plan via <code>/start-work</code></li>
<li>Delegates tasks to specialized agents (Oracle, Frontend Engineer, etc.)</li>
<li>Manages parallel execution waves for efficiency</li>
<li>Tracks progress, handles failures, ensures completion</li>
</ul>
<p class="approach-summary"><strong>You architect. Agents execute. Full transparency.</strong></p>
</div>
</div>
<p>In both cases, the human's job is to <strong>express what they want</strong>, not to manage how it gets done.</p>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 5 -->
<section id="predictable-continuous">
<h2>Predictable, Continuous, Delegatable</h2>
<p><strong>The ideal agent should work like a compiler</strong>: markdown document goes in, working code comes out.</p>
<h3>Predictable</h3>
<p>Given the same inputs:</p>
<ul>
<li>Same codebase patterns</li>
<li>Same requirements</li>
<li>Same constraints</li>
</ul>
<p>...the output should be consistent. Not random, not surprising, not "creative" in ways you didn't ask for.</p>
<h3>Continuous</h3>
<p>Work should survive interruptions:</p>
<ul>
<li>Session crashes? Resume with <code>/start-work</code></li>
<li>Need to step away? Progress is tracked</li>
<li>Multi-day project? Context is preserved</li>
</ul>
<p>The agent maintains state. You don't have to.</p>
<h3>Delegatable</h3>
<p>Just like you can assign a task to a capable team member and trust them to handle it, you should be able to delegate to the agent.</p>
<p>This means:</p>
<ul>
<li>Clear acceptance criteria, verified independently</li>
<li>Self-correcting behavior when something goes wrong</li>
<li>Escalation (to Oracle, to user) only when truly needed</li>
<li>Complete work, not "mostly done"</li>
</ul>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 6 -->
<section id="core-loop">
<h2>The Core Loop</h2>
<div class="ascii-art">
Human Intent → Agent Execution → Verified Result
↑ ↓
└──────── Minimum ─────────────┘
(intervention only on true failure)
</div>
<p>Everything in <a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> is designed to make this loop work:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prometheus</td>
<td>Extract intent through intelligent interview</td>
</tr>
<tr>
<td>Metis</td>
<td>Catch ambiguities before they become bugs</td>
</tr>
<tr>
<td>Momus</td>
<td>Verify plans are complete before execution</td>
</tr>
<tr>
<td>Orchestrator</td>
<td>Coordinate work without human micromanagement</td>
</tr>
<tr>
<td>Todo Continuation</td>
<td>Force completion, prevent "I'm done" lies</td>
</tr>
<tr>
<td>Category System</td>
<td>Route to optimal model without human decision</td>
</tr>
<tr>
<td>Background Agents</td>
<td>Parallel research without blocking user</td>
</tr>
<tr>
<td>Wisdom Accumulation</td>
<td>Learn from work, don't repeat mistakes</td>
</tr>
</tbody>
</table>
</section>
<div class="divider">
<img src="./images/orb-divider.png" alt="Divider">
</div>
<!-- Section 7 -->
<section id="future">
<h2>The Future We're Building</h2>
<p>A world where:</p>
<ul>
<li>Human developers focus on <strong>what</strong> to build, not <strong>how</strong> to get AI to build it</li>
<li>Code quality is independent of who (or what) wrote it</li>
<li>Complex projects are as easy as simple ones (just take longer)</li>
<li>"Prompt engineering" becomes as obsolete as "compiler debugging"</li>
</ul>
<p><strong>The agent should be invisible.</strong> Not in the sense that it's hidden, but in the sense that it just works - like electricity, like running water, like the internet.</p>
<p>You flip the switch. The light turns on. You don't think about the power grid.</p>
<p class="final-statement">That's the goal.</p>
</section>
</main>
<footer>
<div class="footer-content">
<a href="https://github.com/code-yeongyu/oh-my-opencode" class="cta-link" target="_blank" rel="noopener">
Get Oh My OpenCode →
</a>
<p><strong>just ulw ulw</strong></p>
<nav class="language-selector" aria-label="Language selection">
<span class="language-selector-label">Language</span>
<div class="language-links">
<a href="/" class="language-link active" lang="en">English</a>
<a href="/ko/" class="language-link" lang="ko">한국어</a>
<a href="/ja/" class="language-link" lang="ja">日本語</a>
<a href="/zh/" class="language-link" lang="zh">简体中文</a>
<a href="/es/" class="language-link" lang="es">Español</a>
</div>
</nav>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta Tags -->
<title>Ultrawork Manifesto | 高出力エンジニアリングの哲学</title>
<meta name="description" content="開発者とAIエンジニアが、深い集中、原子的実行、そしてUltraworkメソッドを通じて極限の生産性を達成するための哲学的フレームワーク。">
<meta name="keywords" content="ultrawork, 開発者の生産性, AIエンジニアリング, ディープワーク, 技術マニフェスト, oh my opencode, sisyphus">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="en" href="https://ulw.dev/">
<link rel="alternate" hreflang="ko" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="ja" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="zh" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="es" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="x-default" href="https://ulw.dev/">
<meta name="theme-color" content="#0a0a0a">
<meta name="author" content="Yeongyu Kim">
<link rel="icon" type="image/png" href="../images/favicon.png">
<link rel="apple-touch-icon" href="../images/favicon.png">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://ulw.dev/ja/">
<meta property="og:title" content="Ultrawork Manifesto | 高出力エンジニアリングの哲学">
<meta property="og:description" content="開発者とAIエンジニアが、深い集中、原子的実行、そしてUltraworkメソッドを通じて極限の生産性を達成するための哲学的フレームワーク。">
<meta property="og:image" content="https://ulw.dev/images/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Ultrawork Manifesto - 意義ある仕事への青写真">
<meta property="og:site_name" content="Ultrawork">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@justsisyphus">
<meta name="twitter:creator" content="@justsisyphus">
<meta name="twitter:title" content="Ultrawork Manifesto | 高出力エンジニアリングの哲学">
<meta name="twitter:description" content="開発者とAIエンジニアが、深い集中、原子的実行、そしてUltraworkメソッドを通じて極限の生産性を達成するための哲学的フレームワーク。">
<meta name="twitter:image" content="https://ulw.dev/images/og-image.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<header>
<div class="hero-container">
<img src="../images/hero.png" alt="Ultrawork Hero" class="hero-image">
<h1 class="hero-title">Ultrawork Manifesto</h1>
</div>
</header>
<main>
<!-- Section 1 -->
<section id="human-intervention">
<h2>人間の介入は失敗のシグナル</h2>
<div class="gold-gradient-text bottleneck-text">
ヒューマン・イン・ザ・ループ = ボトルネック<br>
ヒューマン・イン・ザ・ループ = ボトルネック<br>
ヒューマン・イン・ザ・ループ = ボトルネック
</div>
<p>自動運転について考えてみてください。人間がハンドルを握らなければならない時、それは機能ではなく、システムの失敗です。車がその状況を自力で処理できなかったのです。</p>
<h3>なぜコーディングは違うと言えるのでしょうか?</h3>
<p>次のような状況に陥った時:</p>
<ul>
<li>AIの中途半端なコードを修正している</li>
<li>明らかな間違いを手動で直している</li>
<li>タスクを通してエージェントを一歩一歩導いている</li>
<li>同じ要件を繰り返し説明している</li>
</ul>
<p>...それは「人間とAIの協調」ではありません。AIが仕事を果たせていないだけです。</p>
<p><strong><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> はこの前提の上に構築されています</strong>:エージェンティックな作業への人間の介入は、根本的に誤ったシグナルです。システムが正しく設計されていれば、エージェントはあなたの子守りを必要とせず、仕事を完遂するはずです。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 2 -->
<section id="indistinguishable-code">
<h2>見分けのつかないコード</h2>
<p class="highlight-box"><strong>目標:エージェントが書いたコードは、シニアエンジニアが書いたコードと見分けがつかないものであるべきです。</strong></p>
<p>「手直しが必要なAI生成コード」ではありません。「良い出発点」でもありません。実際の、最終的な、本番環境で使えるコードです。</p>
<p>これは以下を意味します:</p>
<ul>
<li>既存のコードベースのパターンに正確に従う</li>
<li>指示されなくても適切なエラーハンドリングを行う</li>
<li>実際に正しいことをテストするテストコード</li>
<li>AIによる粗雑なコードオーバーエンジニアリング、不必要な抽象化、スコープクリープがない</li>
<li>価値がある場合にのみコメントを追加する</li>
</ul>
<p>コミットが人間によるものかエージェントによるものか見分けがつくなら、そのエージェントは失敗しています。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 3 -->
<section id="token-cost">
<h2>トークンコスト vs 生産性</h2>
<p><strong>生産性を著しく向上させるのであれば、より高いトークン使用量は許容されます。</strong></p>
<p>より多くのトークンを使って:</p>
<ul>
<li>複数の専門エージェントに並行して調査させる</li>
<li>人間の介入なしに仕事を完全に終わらせる</li>
<li>完了前に作業を徹底的に検証する</li>
<li>タスクを超えて知識を蓄積する</li>
</ul>
<p>...これらは、10倍、20倍、あるいは100倍の生産性向上を意味するのであれば、価値ある投資です。</p>
<h3>しかし:</h3>
<p>不必要なトークンの浪費は追求しません。システムは以下に向けて最適化されます:</p>
<ul>
<li>単純なタスクには安価なモデルHaiku, Flashを使用する</li>
<li>重複する探索を避ける</li>
<li>セッション間で学習内容をキャッシュする</li>
<li>十分なコンテキストが集まったら調査を停止する</li>
</ul>
<p>トークン効率は重要です。しかし、仕事の質や人間の認知的負荷を犠牲にしてまで優先されるべきではありません。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 4 -->
<section id="cognitive-load">
<h2>人間の認知的負荷を最小化する</h2>
<p><strong>人間は「何が欲しいか」を言うだけでいいはずです。それ以外はすべてエージェントの仕事です。</strong></p>
<p>これを達成するための2つのアプローチ</p>
<div class="approach-container">
<div class="approach ultrawork-approach">
<h3>アプローチ 1: Ultrawork</h3>
<p class="approach-tagline">ただ "ulw" と言って立ち去るだけ。</p>
<p>あなたの発言: <code>ulw add authentication</code></p>
<p>エージェントは自律的に:</p>
<ul>
<li>コードベースのパターンとアーキテクチャを分析する</li>
<li>公式ドキュメントからベストプラクティスを調査する</li>
<li>実装戦略を内部的に計画する</li>
<li>既存の規約に従って実装する</li>
<li>テストとLSP診断で検証する</li>
<li>何か問題があれば自己修正する</li>
<li><strong>100%完了するまで岩を押し続ける</strong></li>
</ul>
<p class="approach-summary"><strong>介入ゼロ。完全な自律性。結果だけを。</strong></p>
</div>
<div class="approach prometheus-approach">
<h3>アプローチ 2: Prometheus + Atlas</h3>
<p class="approach-tagline">戦略的なコントロールが必要な時。</p>
<p><kbd>Tab</kbd>を押してエージェントを切り替えた後: <code>add authentication</code></p>
<p><strong>Prometheus</strong> (戦略プランナー):</p>
<ul>
<li>並列エージェントを通じて深いコードベース調査を行う</li>
<li>知的で文脈に沿った質問であなたにインタビューする</li>
<li>エッジケースとアーキテクチャへの影響を特定する</li>
<li>依存関係を含む詳細なYAML作業計画を生成する</li>
</ul>
<p><strong>Atlas</strong> (マスターオーケストレーター):</p>
<ul>
<li><code>/start-work</code> を通じて計画を実行する</li>
<li>専門エージェントOracle, Frontend Engineerなどにタスクを委譲する</li>
<li>効率のために並列実行の波を管理する</li>
<li>進捗を追跡し、失敗を処理し、完了を保証する</li>
</ul>
<p class="approach-summary"><strong>あなたが設計し、エージェントが実行する。完全な透明性。</strong></p>
</div>
</div>
<p>どちらの場合も、人間の仕事は<strong>何が欲しいかを表現すること</strong>であり、どうやってそれを実現するかを管理することではありません。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 5 -->
<section id="predictable-continuous">
<h2>予測可能、継続的、委譲可能</h2>
<p><strong>理想的なエージェントはコンパイラのように動作すべきです</strong>Markdownドキュメントを入力すれば、動作するコードが出力されるのです。</p>
<h3>予測可能</h3>
<p>同じ入力があれば:</p>
<ul>
<li>同じコードベースのパターン</li>
<li>同じ要件</li>
<li>同じ制約</li>
</ul>
<p>...出力は一貫しているべきです。ランダムでも、驚くようなものでもなく、頼んでもいない「創造的」なものであってはなりません。</p>
<h3>継続的</h3>
<p>作業は中断に耐えうるべきです:</p>
<ul>
<li>セッションがクラッシュした? <code>/start-work</code> で再開</li>
<li>席を外す必要がある? 進捗は追跡されています</li>
<li>数日にわたるプロジェクト? コンテキストは保持されます</li>
</ul>
<p>エージェントが状態を維持します。あなたがする必要はありません。</p>
<h3>委譲可能</h3>
<p>優秀なチームメンバーにタスクを割り当てて任せることができるように、エージェントにも委譲できるべきです。</p>
<p>これは以下を意味します:</p>
<ul>
<li>明確な受け入れ基準、独立して検証される</li>
<li>何か問題が起きた時の自己修正動作</li>
<li>本当に必要な時だけのOracleやユーザーへのエスカレーション</li>
<li>「ほぼ完了」ではなく、完全な仕事</li>
</ul>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 6 -->
<section id="core-loop">
<h2>コアループ</h2>
<div class="ascii-art">
人間の意図 → エージェントの実行 → 検証された結果
↑ ↓
└────────── 最小限 ────────────┘
(真の失敗時のみ介入)
</div>
<p>[Oh My OpenCode](https://github.com/code-yeongyu/oh-my-opencode) のすべては、このループを機能させるために設計されています:</p>
<table>
<thead>
<tr>
<th>機能</th>
<th>目的</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prometheus</td>
<td>知的なインタビューを通じて意図を抽出する</td>
</tr>
<tr>
<td>Metis</td>
<td>バグになる前に曖昧さを捉える</td>
</tr>
<tr>
<td>Momus</td>
<td>実行前に計画が完全であることを検証する</td>
</tr>
<tr>
<td>Orchestrator</td>
<td>人間のマイクロマネジメントなしに作業を調整する</td>
</tr>
<tr>
<td>Todo Continuation</td>
<td>完了を強制し、「終わりました」という嘘を防ぐ</td>
</tr>
<tr>
<td>Category System</td>
<td>人間の判断なしに最適なモデルへルーティングする</td>
</tr>
<tr>
<td>Background Agents</td>
<td>ユーザーをブロックせずに並列調査を行う</td>
</tr>
<tr>
<td>Wisdom Accumulation</td>
<td>作業から学び、過ちを繰り返さない</td>
</tr>
</tbody>
</table>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 7 -->
<section id="future">
<h2>私たちが築く未来</h2>
<p>次のような世界:</p>
<ul>
<li>人間の開発者は、AIにどう作らせるかではなく、<strong>何を</strong>作るかに集中する</li>
<li>コードの品質は、誰が(あるいは何が)書いたかとは無関係である</li>
<li>複雑なプロジェクトも単純なプロジェクトと同じくらい簡単になる(ただ時間がかかるだけ)</li>
<li>「プロンプトエンジニアリング」が「コンパイラデバッグ」と同じくらい時代遅れになる</li>
</ul>
<p><strong>エージェントは不可視であるべきです。</strong> 隠されているという意味ではなく、電気や水道、インターネットのように、ただ当たり前に機能するという意味で。</p>
<p>スイッチを入れる。明かりがつく。送電網のことなど考えもしない。</p>
<p class="final-statement">それが目標です。</p>
</section>
</main>
<footer>
<div class="footer-content">
<a href="https://github.com/code-yeongyu/oh-my-opencode" class="cta-link" target="_blank" rel="noopener">
Oh My OpenCode を入手 →
</a>
<p><strong>just ulw ulw</strong></p>
<nav class="language-selector" aria-label="Language selection">
<span class="language-selector-label">Language</span>
<div class="language-links">
<a href="../" class="language-link" lang="en">English</a>
<a href="../ko/" class="language-link" lang="ko">한국어</a>
<a href="./" class="language-link active" lang="ja">日本語</a>
<a href="../zh/" class="language-link" lang="zh">简体中文</a>
<a href="../es/" class="language-link" lang="es">Español</a>
</div>
</nav>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta Tags -->
<title>Ultrawork Manifesto | 고성능 엔지니어링의 철학</title>
<meta name="description" content="개발자와 AI 엔지니어가 깊은 몰입, 원자적 실행, 그리고 Ultrawork 방법론을 통해 극한의 생산성을 달성하기 위한 철학적 프레임워크입니다.">
<meta name="keywords" content="ultrawork, 개발자 생산성, AI 엔지니어링, 딥워크, 기술 선언문, oh my opencode, sisyphus">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="en" href="https://ulw.dev/">
<link rel="alternate" hreflang="ko" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="ja" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="zh" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="es" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="x-default" href="https://ulw.dev/">
<meta name="theme-color" content="#0a0a0a">
<meta name="author" content="Yeongyu Kim">
<link rel="icon" type="image/png" href="../images/favicon.png">
<link rel="apple-touch-icon" href="../images/favicon.png">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://ulw.dev/ko/">
<meta property="og:title" content="Ultrawork Manifesto | 고성능 엔지니어링의 철학">
<meta property="og:description" content="개발자와 AI 엔지니어가 깊은 몰입, 원자적 실행, 그리고 Ultrawork 방법론을 통해 극한의 생산성을 달성하기 위한 철학적 프레임워크입니다.">
<meta property="og:image" content="https://ulw.dev/images/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Ultrawork Manifesto - 의미 있는 작업을 위한 청사진">
<meta property="og:site_name" content="Ultrawork">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@justsisyphus">
<meta name="twitter:creator" content="@justsisyphus">
<meta name="twitter:title" content="Ultrawork Manifesto | 고성능 엔지니어링의 철학">
<meta name="twitter:description" content="개발자와 AI 엔지니어가 깊은 몰입, 원자적 실행, 그리고 Ultrawork 방법론을 통해 극한의 생산성을 달성하기 위한 철학적 프레임워크입니다.">
<meta name="twitter:image" content="https://ulw.dev/images/og-image.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<header>
<div class="hero-container">
<img src="../images/hero.png" alt="Ultrawork Hero" class="hero-image">
<h1 class="hero-title">Ultrawork Manifesto</h1>
</div>
</header>
<main>
<!-- Section 1 -->
<section id="human-intervention">
<h2>인간의 개입은 실패 신호다</h2>
<div class="gold-gradient-text bottleneck-text">
HUMAN IN THE LOOP = BOTTLENECK<br>
HUMAN IN THE LOOP = BOTTLENECK<br>
HUMAN IN THE LOOP = BOTTLENECK
</div>
<p>자율 주행을 생각해 보십시오. 인간이 운전대를 잡아야 한다면, 그것은 기능이 아니라 시스템의 실패입니다. 자동차가 스스로 상황을 감당하지 못한 것입니다.</p>
<h3>코딩이라고 다를 이유가 있습니까?</h3>
<p>당신이 다음과 같은 상황에 처해 있다면:</p>
<ul>
<li>AI가 작성하다 만 코드를 고치고 있거나</li>
<li>뻔한 실수를 직접 수정하고 있거나</li>
<li>에이전트에게 작업을 단계별로 하나하나 지시하고 있거나</li>
<li>같은 요구사항을 반복해서 설명하고 있다면</li>
</ul>
<p>...그것은 "인간과 AI의 협업"이 아닙니다. AI가 제 역할을 못하고 있는 것입니다.</p>
<p><strong><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a>는 이 전제 위에 구축되었습니다</strong>: 에이전트 작업 중 인간의 개입은 근본적으로 잘못된 신호입니다. 시스템이 올바르게 설계되었다면, 에이전트는 당신이 돌봐주지 않아도 작업을 완수해야 합니다.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 2 -->
<section id="indistinguishable-code">
<h2>구별할 수 없는 코드</h2>
<p class="highlight-box"><strong>목표: 에이전트가 작성한 코드는 시니어 엔지니어가 작성한 코드와 구별할 수 없어야 한다.</strong></p>
<p>"정리가 필요한 AI 생성 코드"가 아닙니다. "좋은 시작점"도 아닙니다. 실제, 최종, 프로덕션 준비가 완료된 코드여야 합니다.</p>
<p>이는 다음을 의미합니다:</p>
<ul>
<li>기존 코드베이스 패턴을 정확히 따르는 것</li>
<li>요청하지 않아도 적절한 에러 처리를 하는 것</li>
<li>실제로 필요한 것을 검증하는 테스트를 작성하는 것</li>
<li>AI Slop(과도한 엔지니어링, 불필요한 추상화, 범위 확장)이 없는 것</li>
<li>가치가 있을 때만 주석을 다는 것</li>
</ul>
<p>커밋을 인간이 했는지 에이전트가 했는지 구분할 수 있다면, 그 에이전트는 실패한 것입니다.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 3 -->
<section id="token-cost">
<h2>토큰 비용 vs. 생산성</h2>
<p><strong>생산성을 획기적으로 높일 수 있다면 더 많은 토큰 사용은 허용됩니다.</strong></p>
<p>더 많은 토큰을 사용하여:</p>
<ul>
<li>여러 전문 에이전트가 병렬로 조사하게 하고</li>
<li>인간의 개입 없이 작업을 완전히 끝내고</li>
<li>완료 전에 작업을 철저히 검증하고</li>
<li>작업 전반에 걸쳐 지식을 축적하는 것</li>
</ul>
<p>...이것이 10배, 20배, 100배의 생산성 향상을 의미한다면 가치 있는 투자입니다.</p>
<h3>하지만:</h3>
<p>불필요한 토큰 낭비는 지양합니다. 시스템은 다음을 위해 최적화합니다:</p>
<ul>
<li>단순 작업에는 더 저렴한 모델(Haiku, Flash) 사용</li>
<li>중복 탐색 방지</li>
<li>세션 간 학습 내용 캐싱</li>
<li>충분한 맥락이 수집되면 조사 중단</li>
</ul>
<p>토큰 효율성은 중요합니다. 하지만 작업 품질이나 인간의 인지 부하를 희생해서는 안 됩니다.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 4 -->
<section id="cognitive-load">
<h2>인간의 인지 부하 최소화</h2>
<p><strong>인간은 원하는 것이 무엇인지만 말하면 됩니다. 나머지는 모두 에이전트의 몫입니다.</strong></p>
<p>이를 달성하기 위한 두 가지 접근 방식:</p>
<div class="approach-container">
<div class="approach ultrawork-approach">
<h3>접근 방식 1: Ultrawork</h3>
<p class="approach-tagline">그냥 "ulw"라고 말하고 자리를 비우십시오.</p>
<p>당신이 말합니다: <code>ulw add authentication</code></p>
<p>에이전트는 자율적으로:</p>
<ul>
<li>코드베이스 패턴과 아키텍처를 분석하고</li>
<li>공식 문서에서 모범 사례를 조사하고</li>
<li>내부적으로 구현 전략을 수립하고</li>
<li>기존 컨벤션을 따르며 구현하고</li>
<li>테스트와 LSP 진단으로 검증하고</li>
<li>문제가 생기면 스스로 수정하고</li>
<li><strong>100% 완료될 때까지 계속 밀어붙입니다</strong></li>
</ul>
<p class="approach-summary"><strong>개입 제로. 완전 자율. 오직 결과뿐.</strong></p>
</div>
<div class="approach prometheus-approach">
<h3>접근 방식 2: Prometheus + Atlas</h3>
<p class="approach-tagline">전략적인 제어가 필요할 때.</p>
<p><kbd>Tab</kbd>을 눌러 에이전트를 전환한 뒤: <code>add authentication</code></p>
<p><strong>Prometheus</strong> (전략 기획자):</p>
<ul>
<li>병렬 에이전트를 통해 심층적인 코드베이스 조사를 수행하고</li>
<li>지능적이고 맥락에 맞는 질문으로 당신을 인터뷰하고</li>
<li>엣지 케이스와 아키텍처에 미칠 영향을 식별하고</li>
<li>의존성이 포함된 상세한 YAML 작업 계획을 생성합니다</li>
</ul>
<p><strong>Atlas</strong> (마스터 오케스트레이터):</p>
<ul>
<li><code>/start-work</code>를 통해 계획을 실행하고</li>
<li>전문 에이전트(Oracle, Frontend Engineer 등)에게 작업을 위임하고</li>
<li>효율성을 위해 병렬 실행 웨이브를 관리하고</li>
<li>진행 상황을 추적하고, 실패를 처리하며, 완료를 보장합니다</li>
</ul>
<p class="approach-summary"><strong>당신은 설계하고, 에이전트는 실행합니다. 완전한 투명성.</strong></p>
</div>
</div>
<p>두 경우 모두, 인간의 역할은 <strong>원하는 것을 표현하는 것</strong>이지, 어떻게 할지를 관리하는 것이 아닙니다.</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 5 -->
<section id="predictable-continuous">
<h2>예측 가능성, 지속성, 위임 가능성</h2>
<p><strong>이상적인 에이전트는 컴파일러처럼 작동해야 합니다</strong>: 마크다운 문서가 들어가면, 작동하는 코드가 나와야 합니다.</p>
<h3>예측 가능성 (Predictable)</h3>
<p>동일한 입력이 주어졌을 때:</p>
<ul>
<li>동일한 코드베이스 패턴</li>
<li>동일한 요구사항</li>
<li>동일한 제약조건</li>
</ul>
<p>...출력은 일관되어야 합니다. 무작위적이거나, 놀랍거나, 요청하지 않은 방식으로 "창의적"이어서는 안 됩니다.</p>
<h3>지속성 (Continuous)</h3>
<p>작업은 중단되어도 지속되어야 합니다:</p>
<ul>
<li>세션이 충돌했나요? <code>/start-work</code>로 재개하십시오</li>
<li>자리를 비워야 하나요? 진행 상황은 추적됩니다</li>
<li>며칠 걸리는 프로젝트인가요? 맥락은 보존됩니다</li>
</ul>
<p>상태 유지는 에이전트가 합니다. 당신이 할 필요가 없습니다.</p>
<h3>위임 가능성 (Delegatable)</h3>
<p>유능한 팀원에게 업무를 맡기고 믿는 것처럼, 에이전트에게도 위임할 수 있어야 합니다.</p>
<p>이는 다음을 의미합니다:</p>
<ul>
<li>독립적으로 검증된 명확한 인수 조건</li>
<li>문제가 발생했을 때의 자가 수정 행동</li>
<li>정말 필요할 때만 (Oracle이나 사용자에게) 에스컬레이션</li>
<li>"거의 다 된" 것이 아닌, 완전히 끝난 작업</li>
</ul>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 6 -->
<section id="core-loop">
<h2>핵심 루프 (The Core Loop)</h2>
<div class="ascii-art">
Human Intent → Agent Execution → Verified Result
↑ ↓
└──────── Minimum ─────────────┘
(intervention only on true failure)
</div>
<p><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a>의 모든 것은 이 루프가 작동하도록 설계되었습니다:</p>
<table>
<thead>
<tr>
<th>기능</th>
<th>목적</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prometheus</td>
<td>지능형 인터뷰를 통해 의도 추출</td>
</tr>
<tr>
<td>Metis</td>
<td>버그가 되기 전에 모호함 포착</td>
</tr>
<tr>
<td>Momus</td>
<td>실행 전 계획의 완전성 검증</td>
</tr>
<tr>
<td>Orchestrator</td>
<td>인간의 마이크로매니지먼트 없이 작업 조정</td>
</tr>
<tr>
<td>Todo Continuation</td>
<td>완료를 강제하고, "다 했어요"라는 거짓말 방지</td>
</tr>
<tr>
<td>Category System</td>
<td>인간의 결정 없이 최적의 모델로 라우팅</td>
</tr>
<tr>
<td>Background Agents</td>
<td>사용자를 차단하지 않고 병렬 조사</td>
</tr>
<tr>
<td>Wisdom Accumulation</td>
<td>작업에서 학습하여 실수 반복 방지</td>
</tr>
</tbody>
</table>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 7 -->
<section id="future">
<h2>우리가 만드는 미래</h2>
<p>다음과 같은 세상입니다:</p>
<ul>
<li>인간 개발자는 AI에게 어떻게 만들게 할지가 아니라, <strong>무엇</strong>을 만들지에 집중합니다</li>
<li>코드 품질이 누가(또는 무엇이) 작성했는지와 무관합니다</li>
<li>복잡한 프로젝트도 단순한 프로젝트만큼 쉽습니다 (단지 시간이 더 걸릴 뿐)</li>
<li>"프롬프트 엔지니어링"이 "컴파일러 디버깅"만큼이나 구시대의 유물이 됩니다</li>
</ul>
<p><strong>에이전트는 보이지 않아야 합니다.</strong> 숨겨져 있다는 뜻이 아니라, 전기나 수돗물, 인터넷처럼 그저 작동한다는 의미에서 그렇습니다.</p>
<p>스위치를 켜면 불이 들어옵니다. 전력망에 대해서는 생각하지 않습니다.</p>
<p class="final-statement">그것이 목표입니다.</p>
</section>
</main>
<footer>
<div class="footer-content">
<a href="https://github.com/code-yeongyu/oh-my-opencode" class="cta-link" target="_blank" rel="noopener">
Oh My OpenCode 받기 →
</a>
<p><strong>just ulw ulw</strong></p>
<nav class="language-selector" aria-label="Language selection">
<span class="language-selector-label">Language</span>
<div class="language-links">
<a href="../" class="language-link" lang="en">English</a>
<a href="./" class="language-link active" lang="ko">한국어</a>
<a href="../ja/" class="language-link" lang="ja">日本語</a>
<a href="../zh/" class="language-link" lang="zh">简体中文</a>
<a href="../es/" class="language-link" lang="es">Español</a>
</div>
</nav>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,674 @@
/* Design System */
:root {
/* Colors */
--bg-primary: #030303; /* Darker, deeper black */
--bg-secondary: #0a0a0a;
--text-primary: #ffffff;
--text-secondary: #a1a1aa;
--text-muted: #52525b;
/* Accents */
--accent-cyan: #64D2FF; /* More refined cyan */
--accent-cyan-dim: rgba(100, 210, 255, 0.1);
--accent-gold: #F5D061; /* Premium gold */
--accent-gold-dim: rgba(245, 208, 97, 0.1);
/* Gradients */
--gold-gradient: linear-gradient(135deg, #F5D061 0%, #E1B32E 100%);
--cyan-gradient: linear-gradient(135deg, #64D2FF 0%, #2E93E1 100%);
--dark-gradient: linear-gradient(to bottom, #050505, #0a0a0a);
/* Typography */
--font-serif: 'Cormorant Garamond', serif;
--font-sans: 'Inter', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
/* Spacing */
--spacing-section: 160px; /* Increased breathing room */
--max-width: 1100px; /* Slightly wider for drama */
/* Glassmorphism */
--glass-bg: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08);
--glass-blur: 12px;
/* Glows */
--glow-cyan: 0 0 40px rgba(100, 210, 255, 0.15);
--glow-gold: 0 0 40px rgba(245, 208, 97, 0.15);
--radial-glow: radial-gradient(circle at center, rgba(100, 210, 255, 0.08) 0%, transparent 70%);
}
/* Reset & Base */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
font-family: var(--font-sans);
line-height: 1.7;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* Noise Texture Overlay */
body::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
opacity: 0.03;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
}
/* Typography */
h1, h2, h3 {
font-family: var(--font-serif);
font-weight: 600;
line-height: 1.1;
letter-spacing: -0.02em;
}
h1 {
font-size: clamp(4rem, 8vw, 7rem);
background: linear-gradient(to bottom, #fff 0%, #ccc 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 80px rgba(255, 255, 255, 0.1);
}
h2 {
font-size: 3.5rem;
margin-bottom: 2rem;
color: #fff;
}
h3 {
font-family: var(--font-sans);
font-size: 1.25rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--accent-gold);
margin-top: 3rem;
margin-bottom: 1.5rem;
}
p {
font-size: 1.25rem;
color: var(--text-secondary);
margin-bottom: 2rem;
max-width: 65ch;
line-height: 1.8;
}
strong {
color: #fff;
font-weight: 600;
}
a {
color: var(--accent-cyan);
text-decoration: none;
transition: color 0.2s ease;
}
a:hover {
color: #fff;
text-decoration: underline;
}
a:focus-visible {
outline: 2px solid var(--accent-cyan);
outline-offset: 2px;
border-radius: 2px;
}
/* Layout */
header {
max-width: var(--max-width);
margin: 0 auto;
padding: 8rem 2rem 4rem;
position: relative;
}
.hero-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 2.5rem;
position: relative;
}
/* Hero glow effect */
.hero-container::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 120%;
height: 120%;
background: var(--radial-glow);
pointer-events: none;
z-index: -1;
}
.hero-image {
width: 100%;
max-width: 700px;
height: auto;
border-radius: 16px;
opacity: 0.95;
animation: fadeUp 1s cubic-bezier(0.2, 0.8, 0.2, 1);
box-shadow: var(--glow-cyan);
}
.hero-title {
font-size: clamp(2.5rem, 5vw, 4rem);
margin-bottom: 0;
animation: fadeUp 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) 0.2s both;
}
main {
max-width: var(--max-width);
margin: 0 auto;
padding: 2rem 2rem 0;
}
section {
margin-bottom: var(--spacing-section);
}
/* Components */
.divider {
display: flex;
justify-content: center;
align-items: center;
margin: var(--spacing-section) 0;
position: relative;
height: 2px;
}
.divider::before {
content: "";
position: absolute;
width: 100%;
max-width: 400px;
height: 1px;
background: linear-gradient(90deg, transparent 0%, var(--accent-cyan) 20%, var(--accent-gold) 80%, transparent 100%);
opacity: 0.5;
}
.divider::after {
content: "";
position: absolute;
width: 8px;
height: 8px;
background: var(--accent-cyan);
border-radius: 50%;
box-shadow: var(--glow-cyan);
}
.divider img {
display: none;
}
/* Feature: Gold Gradient Text */
.gold-gradient-text {
font-family: var(--font-mono);
font-size: 1.2rem;
line-height: 1.6;
text-align: center;
padding: 3rem;
margin: 3rem 0;
border: 1px solid var(--accent-gold-dim);
background: radial-gradient(circle at center, rgba(245, 208, 97, 0.03) 0%, transparent 70%);
border-radius: 2px;
position: relative;
}
.gold-gradient-text::before, .gold-gradient-text::after {
content: "+";
position: absolute;
color: var(--accent-gold);
opacity: 0.5;
}
.gold-gradient-text::before { top: -10px; left: -5px; }
.gold-gradient-text::after { bottom: -10px; right: -5px; }
.bottleneck-text {
background: var(--gold-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 700;
letter-spacing: 0.1em;
}
/* Feature: Highlight Box */
.highlight-box {
border-left: 2px solid var(--accent-cyan);
font-style: italic;
color: #fff;
background: linear-gradient(90deg, var(--accent-cyan-dim) 0%, transparent 100%);
padding: 2rem;
border-radius: 0 8px 8px 0;
}
/* Feature: Cards */
.approach-container {
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
margin-top: 3rem;
}
@media (min-width: 768px) {
.approach-container { grid-template-columns: 1fr 1fr; }
}
.approach {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
padding: 3rem;
border-radius: 20px;
transition: all 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
position: relative;
overflow: hidden;
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
}
.approach:hover {
transform: translateY(-8px);
background: rgba(255, 255, 255, 0.05);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: 0 25px 50px -15px rgba(0,0,0,0.6);
}
.ultrawork-approach:hover {
border-color: var(--accent-cyan);
box-shadow: var(--glow-cyan), 0 25px 50px -15px rgba(0,0,0,0.6);
}
.prometheus-approach:hover {
border-color: var(--accent-gold);
box-shadow: var(--glow-gold), 0 25px 50px -15px rgba(0,0,0,0.6);
}
.approach h3 {
margin-top: 0;
font-size: 1.5rem;
color: #fff;
font-family: var(--font-serif);
}
.approach-tagline {
font-family: var(--font-mono);
font-size: 0.9rem;
color: var(--text-muted);
margin-bottom: 2rem;
}
/* Lists */
ul {
list-style: none;
padding-left: 1rem;
}
ul li {
position: relative;
padding-left: 1.5rem;
margin-bottom: 1rem;
color: var(--text-secondary);
}
ul li::before {
content: "•";
position: absolute;
left: 0;
color: var(--accent-cyan);
}
.prometheus-approach ul li::before { color: var(--accent-gold); }
/* Code & ASCII */
code {
font-family: var(--font-mono);
color: var(--accent-cyan);
background: rgba(100, 210, 255, 0.1);
padding: 0.2em 0.4em;
border-radius: 4px;
font-size: 0.9em;
}
kbd {
font-family: var(--font-mono);
font-size: 0.85em;
color: var(--text-primary);
background: linear-gradient(180deg, #3a3a3a 0%, #222 100%);
padding: 0.15em 0.5em;
border-radius: 4px;
border: 1px solid #555;
box-shadow: 0 2px 0 #111, inset 0 1px 0 rgba(255,255,255,0.1);
}
.ascii-art {
font-family: var(--font-mono);
font-size: 0.85rem;
line-height: 1.4;
color: var(--accent-cyan);
background: #000;
padding: 2rem;
border: 1px solid #333;
border-radius: 8px;
overflow-x: auto;
box-shadow: inset 0 0 20px rgba(0,0,0,0.8);
}
/* Table */
table {
width: 100%;
border-collapse: collapse;
margin: 3rem 0;
font-family: var(--font-sans);
}
th {
text-align: left;
padding: 1.5rem;
border-bottom: 1px solid #333;
color: var(--accent-gold);
font-family: var(--font-mono);
font-size: 0.9rem;
text-transform: uppercase;
}
td {
padding: 1.5rem;
border-bottom: 1px solid #222;
color: var(--text-secondary);
}
tr:hover td {
background: rgba(255, 255, 255, 0.02);
color: #fff;
}
/* Footer */
footer {
margin-top: var(--spacing-section);
padding: 8rem 2rem;
text-align: center;
position: relative;
overflow: hidden;
background: radial-gradient(ellipse at center bottom, rgba(100, 210, 255, 0.05) 0%, transparent 60%);
}
footer::before {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, var(--accent-cyan-dim), var(--accent-gold-dim), transparent);
}
.footer-content {
position: relative;
z-index: 2;
}
.footer-pattern {
display: none;
}
a.cta-link,
a.cta-link:hover,
a.cta-link:focus,
a.cta-link:active {
display: inline-block;
padding: 1.2rem 3rem;
background: var(--text-primary);
color: #000;
font-weight: 600;
text-decoration: none;
border-radius: 50px;
transition: all 0.3s ease;
margin-bottom: 2rem;
position: relative;
z-index: 3;
}
a.cta-link:hover {
transform: scale(1.05);
box-shadow: 0 0 40px rgba(255, 255, 255, 0.4), var(--glow-cyan);
}
.final-statement {
font-family: var(--font-serif);
font-size: 2.5rem;
font-style: italic;
color: var(--text-muted);
}
/* Animations */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
/* ===== RESPONSIVE DESIGN ===== */
/* Tablet */
@media (max-width: 1024px) {
:root {
--max-width: 90%;
--spacing-section: 100px;
}
h1 { font-size: clamp(3rem, 6vw, 5rem); }
h2 { font-size: 2.5rem; }
}
/* Mobile Landscape / Small Tablet */
@media (max-width: 768px) {
:root {
--spacing-section: 80px;
}
header {
padding: 4rem 1.5rem 2rem;
}
main {
padding: 1.5rem 1.5rem 0;
}
h2 { font-size: 2rem; }
.hero-image {
max-width: 100%;
}
.approach-container {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.approach {
padding: 2rem;
}
.divider::before {
max-width: 250px;
}
/* Table to card layout */
table, thead, tbody, th, td, tr {
display: block;
}
thead {
display: none;
}
tr {
margin-bottom: 1.5rem;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 12px;
padding: 1rem;
}
td {
padding: 0.75rem 0;
border-bottom: none;
position: relative;
}
td:first-child {
color: var(--accent-gold);
font-weight: 600;
font-size: 1rem;
}
td:last-child {
color: var(--text-secondary);
font-size: 0.95rem;
}
}
/* Mobile Portrait */
@media (max-width: 480px) {
:root {
--spacing-section: 60px;
}
header {
padding: 2rem 1rem 1rem;
}
main {
padding: 1rem 1rem 0;
}
h1 { font-size: 2rem; }
h2 { font-size: 1.75rem; }
h3 { font-size: 1.1rem; }
p {
font-size: 1.1rem;
}
.gold-gradient-text {
padding: 1.5rem;
font-size: 0.9rem;
}
.highlight-box {
padding: 1.25rem;
}
.approach {
padding: 1.5rem;
}
.approach h3 {
font-size: 1.25rem;
}
.approach-tagline {
font-size: 0.8rem;
}
.ascii-art {
font-size: 0.7rem;
padding: 1rem;
overflow-x: auto;
}
.cta-link {
padding: 1rem 2rem;
font-size: 0.95rem;
}
.final-statement {
font-size: 1.75rem;
}
footer {
padding: 4rem 1rem;
}
}
/* ===== LANGUAGE SELECTOR ===== */
.language-selector {
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--glass-border);
}
.language-selector-label {
font-family: var(--font-mono);
font-size: 0.75rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.15em;
margin-bottom: 1rem;
display: block;
}
.language-links {
display: flex;
justify-content: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.language-link {
font-family: var(--font-sans);
font-size: 0.9rem;
color: var(--text-secondary);
padding: 0.5rem 1rem;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 8px;
transition: all 0.3s ease;
text-decoration: none;
backdrop-filter: blur(var(--glass-blur));
-webkit-backdrop-filter: blur(var(--glass-blur));
}
.language-link:hover {
color: var(--text-primary);
background: rgba(255, 255, 255, 0.08);
border-color: var(--accent-cyan);
box-shadow: var(--glow-cyan);
text-decoration: none;
}
.language-link.active {
color: var(--accent-cyan);
border-color: var(--accent-cyan);
background: rgba(100, 210, 255, 0.08);
}
/* Mobile responsive for language selector */
@media (max-width: 480px) {
.language-links {
gap: 0.4rem;
}
.language-link {
font-size: 0.8rem;
padding: 0.4rem 0.8rem;
}
}

View File

@@ -0,0 +1,341 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta Tags -->
<title>Ultrawork Manifesto | 高产出工程哲学</title>
<meta name="description" content="一个为开发者和 AI 工程师设计的哲学框架,通过深度专注、原子化执行和 Ultrawork 方法论实现极致生产力。">
<meta name="keywords" content="ultrawork, 开发者生产力, AI 工程, 深度工作, 技术宣言, oh my opencode, sisyphus">
<meta name="robots" content="index, follow, max-image-preview:large">
<link rel="canonical" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="en" href="https://ulw.dev/">
<link rel="alternate" hreflang="ko" href="https://ulw.dev/ko/">
<link rel="alternate" hreflang="ja" href="https://ulw.dev/ja/">
<link rel="alternate" hreflang="zh" href="https://ulw.dev/zh/">
<link rel="alternate" hreflang="es" href="https://ulw.dev/es/">
<link rel="alternate" hreflang="x-default" href="https://ulw.dev/">
<meta name="theme-color" content="#0a0a0a">
<meta name="author" content="Yeongyu Kim">
<link rel="icon" type="image/png" href="../images/favicon.png">
<link rel="apple-touch-icon" href="../images/favicon.png">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://ulw.dev/zh/">
<meta property="og:title" content="Ultrawork Manifesto | 高产出工程哲学">
<meta property="og:description" content="一个为开发者和 AI 工程师设计的哲学框架,通过深度专注、原子化执行和 Ultrawork 方法论实现极致生产力。">
<meta property="og:image" content="https://ulw.dev/images/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Ultrawork Manifesto - 有意义工作的蓝图">
<meta property="og:site_name" content="Ultrawork">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@justsisyphus">
<meta name="twitter:creator" content="@justsisyphus">
<meta name="twitter:title" content="Ultrawork Manifesto | 高产出工程哲学">
<meta name="twitter:description" content="一个为开发者和 AI 工程师设计的哲学框架,通过深度专注、原子化执行和 Ultrawork 方法论实现极致生产力。">
<meta name="twitter:image" content="https://ulw.dev/images/og-image.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<header>
<div class="hero-container">
<img src="../images/hero.png" alt="Ultrawork Hero" class="hero-image">
<h1 class="hero-title">Ultrawork Manifesto</h1>
</div>
</header>
<main>
<!-- Section 1 -->
<section id="human-intervention">
<h2>人工干预是失败的信号</h2>
<div class="gold-gradient-text bottleneck-text">
人在回路即瓶颈<br>
人在回路即瓶颈<br>
人在回路即瓶颈
</div>
<p>试想一下自动驾驶。当人类必须接管方向盘时,这并非一项功能——而是系统的失败。这意味着汽车无法独自应对当前状况。</p>
<h3>编程又有何不同?</h3>
<p>当你发现自己正在:</p>
<ul>
<li>修复 AI 半成品的代码</li>
<li>手动修正明显的错误</li>
<li>一步步引导 Agent 完成任务</li>
<li>反复澄清相同的需求</li>
</ul>
<p>……这不叫“人机协作”。这是 AI 未能履行其职责。</p>
<p><strong><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> 正是基于这一前提构建的</strong>:在 Agent 工作期间人工干预本质上是一个错误的信号。如果系统设计得当Agent 应当能够独立完成工作,而无需你像保姆一样照看。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 2 -->
<section id="indistinguishable-code">
<h2>无法区分的代码</h2>
<p class="highlight-box"><strong>目标Agent 编写的代码应与高级工程师编写的代码无法区分。</strong></p>
<p>不是“需要清理的 AI 生成代码”。不是“一个好的起点”。而是真正的、最终的、生产就绪的代码。</p>
<p>这意味着:</p>
<ul>
<li>严格遵循现有的代码库模式</li>
<li>无需被要求即可进行恰当的错误处理</li>
<li>编写真正测试核心逻辑的测试用例</li>
<li>拒绝 AI 垃圾代码(过度设计、不必要的抽象、范围蔓延)</li>
<li>仅在有价值时添加注释</li>
</ul>
<p>如果你能分辨出一次提交是由人类还是 Agent 完成的,那么这个 Agent 就失败了。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 3 -->
<section id="token-cost">
<h2>Token 成本 vs. 生产力</h2>
<p><strong>如果能显著提高生产力,较高的 Token 使用量是可以接受的。</strong></p>
<p>使用更多的 Token 来:</p>
<ul>
<li>让多个专业 Agent 并行研究</li>
<li>在无人工干预的情况下彻底完成工作</li>
<li>在完成前彻底验证工作</li>
<li>跨任务积累知识</li>
</ul>
<p>……当这意味着 10 倍、20 倍甚至 100 倍的生产力提升时,这是一笔值得的投资。</p>
<h3>然而:</h3>
<p>我们不追求无谓的 Token 浪费。系统致力于优化:</p>
<ul>
<li>对简单任务使用更便宜的模型Haiku, Flash</li>
<li>避免冗余的探索</li>
<li>跨会话缓存学习成果</li>
<li>当收集到足够上下文时停止研究</li>
</ul>
<p>Token 效率很重要。但绝不能以牺牲工作质量或人类认知负荷为代价。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 4 -->
<section id="cognitive-load">
<h2>最小化人类认知负荷</h2>
<p><strong>人类只需要说出他们想要什么。其余的一切都是 Agent 的工作。</strong></p>
<p>实现这一点的两种方法:</p>
<div class="approach-container">
<div class="approach ultrawork-approach">
<h3>方法 1Ultrawork</h3>
<p class="approach-tagline">只需说 "ulw" 然后走开。</p>
<p>你说:<code>ulw add authentication</code></p>
<p>Agent 自主地:</p>
<ul>
<li>分析你的代码库模式和架构</li>
<li>从官方文档研究最佳实践</li>
<li>内部规划实施策略</li>
<li>遵循你现有的惯例进行实现</li>
<li>使用测试和 LSP 诊断进行验证</li>
<li>出错时自我修正</li>
<li><strong>坚持攻坚,直到 100% 完成</strong></li>
</ul>
<p class="approach-summary"><strong>零干预。全自主。只看结果。</strong></p>
</div>
<div class="approach prometheus-approach">
<h3>方法 2Prometheus + Atlas</h3>
<p class="approach-tagline">当你想要战略控制权时。</p>
<p><kbd>Tab</kbd> 切换 Agent 后:<code>add authentication</code></p>
<p><strong>Prometheus</strong>(战略规划者):</p>
<ul>
<li>通过并行 Agent 进行深度代码库研究</li>
<li>用智能的、结合上下文的问题采访你</li>
<li>识别边缘情况和架构影响</li>
<li>生成带有依赖关系的详细 YAML 工作计划</li>
</ul>
<p><strong>Atlas</strong>(首席编排者):</p>
<ul>
<li>通过 <code>/start-work</code> 执行计划</li>
<li>将任务委派给专业 AgentOracle, 前端工程师等)</li>
<li>管理并行执行波次以提高效率</li>
<li>追踪进度,处理失败,确保完成</li>
</ul>
<p class="approach-summary"><strong>你来架构。Agent 执行。完全透明。</strong></p>
</div>
</div>
<p>在这两种情况下,人类的工作是<strong>表达他们想要什么</strong>,而不是管理如何完成。</p>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 5 -->
<section id="predictable-continuous">
<h2>可预测,连续性,可委派</h2>
<p><strong>理想的 Agent 应该像编译器一样工作</strong>:输入 Markdown 文档,输出可工作的代码。</p>
<h3>可预测 (Predictable)</h3>
<p>给定相同的输入:</p>
<ul>
<li>相同的代码库模式</li>
<li>相同的需求</li>
<li>相同的约束</li>
</ul>
<p>……输出应该是一致的。不是随机的,不是令人惊讶的,也不是在你未要求的地方“发挥创意”。</p>
<h3>连续性 (Continuous)</h3>
<p>工作应能经受住中断:</p>
<ul>
<li>会话崩溃?用 <code>/start-work</code> 恢复</li>
<li>需要离开?进度会被追踪</li>
<li>多日项目?上下文会被保留</li>
</ul>
<p>Agent 维护状态。你不需要。</p>
<h3>可委派 (Delegatable)</h3>
<p>就像你可以把任务分配给得力的团队成员并信任他们能搞定一样,你应该能够委派给 Agent。</p>
<p>这意味着:</p>
<ul>
<li>清晰的验收标准,独立验证</li>
<li>出错时的自我修正行为</li>
<li>仅在真正需要时升级(给 Oracle给用户</li>
<li>完成工作,而不是“差不多做完了”</li>
</ul>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 6 -->
<section id="core-loop">
<h2>核心循环</h2>
<div class="ascii-art">
人类意图 → Agent 执行 → 验证结果
↑ ↓
└─────── 最小化 ───────┘
(仅在真正失败时干预)
</div>
<p><a href="https://github.com/code-yeongyu/oh-my-opencode" target="_blank" rel="noopener">Oh My OpenCode</a> 中的一切都是为了让这个循环运转而设计的:</p>
<table>
<thead>
<tr>
<th>功能</th>
<th>目的</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prometheus</td>
<td>通过智能访谈提取意图</td>
</tr>
<tr>
<td>Metis</td>
<td>在歧义变成 Bug 之前捕捉它们</td>
</tr>
<tr>
<td>Momus</td>
<td>在执行前验证计划是否完整</td>
</tr>
<tr>
<td>Orchestrator</td>
<td>协调工作,无需人类微观管理</td>
</tr>
<tr>
<td>Todo Continuation</td>
<td>强制完成,防止“我做完了”的谎言</td>
</tr>
<tr>
<td>Category System</td>
<td>无需人工决策即可路由至最佳模型</td>
</tr>
<tr>
<td>Background Agents</td>
<td>并行研究而不阻塞用户</td>
</tr>
<tr>
<td>Wisdom Accumulation</td>
<td>从工作中学习,不重复错误</td>
</tr>
</tbody>
</table>
</section>
<div class="divider">
<img src="../images/orb-divider.png" alt="Divider">
</div>
<!-- Section 7 -->
<section id="future">
<h2>我们正在构建的未来</h2>
<p>一个这样的世界:</p>
<ul>
<li>人类开发者专注于<strong>构建什么</strong>,而不是<strong>如何</strong>让 AI 去构建它</li>
<li>代码质量与谁(或什么)编写了它无关</li>
<li>复杂项目像简单项目一样容易(只是耗时更长)</li>
<li>“提示词工程”变得像“编译器调试”一样过时</li>
</ul>
<p><strong>Agent 应该是隐形的。</strong> 不是说它被隐藏起来了,而是说它自然而然地工作——就像电,像自来水,像互联网。</p>
<p>你按下开关。灯亮了。你不会去思考电网。</p>
<p class="final-statement">这就是目标。</p>
</section>
</main>
<footer>
<div class="footer-content">
<a href="https://github.com/code-yeongyu/oh-my-opencode" class="cta-link" target="_blank" rel="noopener">
获取 Oh My OpenCode →
</a>
<p><strong>just ulw ulw</strong></p>
<nav class="language-selector" aria-label="Language selection">
<span class="language-selector-label">语言</span>
<div class="language-links">
<a href="../" class="language-link" lang="en">English</a>
<a href="../ko/" class="language-link" lang="ko">한국어</a>
<a href="../ja/" class="language-link" lang="ja">日本語</a>
<a href="./" class="language-link active" lang="zh">简体中文</a>
<a href="../es/" class="language-link" lang="es">Español</a>
</div>
</nav>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,3 @@
name = "ultrawork-manifesto"
compatibility_date = "2024-01-01"
pages_build_output_dir = "./src"