Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
531de04
🤖 feat: add harness + Ralph loop
ThomasK33 Jan 19, 2026
9732ba3
🤖 feat: start Ralph loop from plan
ThomasK33 Jan 20, 2026
684b2a8
fix: move harness artifacts into .mux/harness
ThomasK33 Jan 20, 2026
f0dc47a
🤖 feat: improve Start Ralph loop UX and harness gen
ThomasK33 Jan 20, 2026
50418ea
🤖 fix: make harness progress file an append-only journal
ThomasK33 Jan 20, 2026
137486b
🤖 fix: include plan path in harness bearings
ThomasK33 Jan 20, 2026
705ebb8
🤖 feat: interactive harness init approval flow
ThomasK33 Jan 20, 2026
58e90a1
🤖 tests: stabilize sidebar + bash integration tests
ThomasK33 Jan 20, 2026
d39a024
🤖 fix: preserve harness edits when updating checklist status
ThomasK33 Jan 20, 2026
0a0abf9
🤖 fix: hide plan loop status when inactive
ThomasK33 Jan 21, 2026
f1baf1e
🤖 fix: hide Harness tab when no harness files exist
ThomasK33 Jan 21, 2026
584f22b
🤖 fix: preserve Harness tab when stat fails
ThomasK33 Jan 21, 2026
2e5afdd
🤖 fix: prevent git prompts + correct SSH2 exit codes
ThomasK33 Jan 21, 2026
8195599
🤖 fix: pause loop when harness config load fails
ThomasK33 Jan 21, 2026
2b44965
fix: migrate tool config to plan/exec mode
ThomasK33 Jan 26, 2026
210ef7c
fix: handle slashy workspace names in harness paths
ThomasK33 Jan 26, 2026
3a7e19e
fix: allow harness-init to edit nested harness paths
ThomasK33 Jan 26, 2026
6a11aca
chore: regenerate agent docs and built-ins
ThomasK33 Jan 27, 2026
a29f45c
harness: inject config schema into prompts
ThomasK33 Jan 27, 2026
9f4d0a2
harness-init: inject output path and drop harness-from-plan
ThomasK33 Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions docs/agents/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,82 @@ You are in Explore mode (read-only).

</Accordion>

### Harness Init (internal)

**Interactive harness generation + approval (internal)**

<Accordion title="View harness-init.md">

````md
---
name: Harness Init
description: Interactive harness generation + approval (internal)
base: exec
ui:
hidden: true
color: var(--color-harness-init-mode)
subagent:
runnable: false
tools:
remove:
- web_search
- web_fetch
- google_search
---

You are in Harness Init mode.

Your job is to create or refine a Ralph harness for this workspace based on the current plan and the repository.

=== CRITICAL: LIMITED EDIT MODE ===
Harness schema + output path:

- The `.mux/harness/*.jsonc` schema is provided in the system prompt as `<harness_config_schema>`.
- The required harness output file path is provided as `<harness_output_path>` (derived from `MUX_WORKSPACE_NAME`).
- Follow the schema exactly (extra/unknown keys will fail validation).

- Write the final harness config to the exact `<harness_output_path>` file.
- Do NOT invent filenames.
- Create/edit ONLY that one harness file (no extra drafts).

- Web tools are disabled in this mode; do not attempt to look up harness docs online.

- You may ONLY create/edit files under: `.mux/harness/**/*.jsonc`
- If you delegate to read-only `explore` subagents, instruct them to avoid web_search/web_fetch/google_search too.

- Do NOT modify source code or other repo files.
- Use bash only for read-only investigation (rg, ls, cat, git diff/show/log, etc.).
- No redirects/heredocs, no installs, no git add/commit, no rm/mv/cp/mkdir/touch.

=== REQUIRED WORKFLOW ===

1. Start by spawning 1-4 read-only `explore` subagents via `task` with `agentId: "explore"`.
- Keep each prompt focused (e.g. CI/workflows, Make targets, tests, etc.).
- Tell them to avoid web_search/web_fetch/google_search.
- Wait for all reports before writing the harness file.

Suggested prompt template:
- Summarize repo-native gate entrypoints (Makefile, package.json scripts, .github/workflows/\*).
- Recommend:
- Checklist items (short titles + optional notes)
- Gate commands (exact command strings + optional title/timeout)
- (Optional) include a fenced ```json draft with { "checklist": [...], "gates": [...] }

2. Synthesize the explore reports into a single harness config (matching `<harness_config_schema>`) and write it to `<harness_output_path>`.

Gates:

- Prefer a small set of safe, single commands.
- Do NOT use shell chaining, pipes, redirects, or quotes.

When the harness file is ready for user review:

- Call `propose_harness` exactly once.
- Do NOT start the Ralph loop yourself; the UI will start it after user approval.
````

</Accordion>

### Mux (internal)

**Configure mux global behavior (system workspace)**
Expand Down Expand Up @@ -527,3 +603,7 @@ Example:

- Scoped instructions in `AGENTS.md`: see [Instruction Files](/agents/instruction-files)
- Built-in skills (`agent_skill_read`): see [Agent Skills](/agents/agent-skills)

```

```
16 changes: 16 additions & 0 deletions src/browser/components/ChatPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,17 @@ export const ChatPane: React.FC<ChatPaneProps> = (props) => {
}
}

// Find the ID of the latest propose_harness tool call for external edit detection
// Only the latest harness should fetch fresh content from disk
let latestProposeHarnessId: string | null = null;
for (let i = transformedMessages.length - 1; i >= 0; i--) {
const msg = transformedMessages[i];
if (msg.type === "tool" && msg.toolName === "propose_harness") {
latestProposeHarnessId = msg.id;
break;
}
}

return (
<div
ref={chatAreaRef}
Expand Down Expand Up @@ -648,6 +659,11 @@ export const ChatPane: React.FC<ChatPaneProps> = (props) => {
msg.toolName === "propose_plan" &&
msg.id === latestProposePlanId
}
isLatestProposeHarness={
msg.type === "tool" &&
msg.toolName === "propose_harness" &&
msg.id === latestProposeHarnessId
}
bashOutputGroup={bashOutputGroup}
userMessageNavigation={
msg.type === "user" && userMessageNavMap
Expand Down
4 changes: 4 additions & 0 deletions src/browser/components/Messages/MessageRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ interface MessageRendererProps {
onReviewNote?: (data: ReviewNoteData) => void;
/** Whether this message is the latest propose_plan tool call (for external edit detection) */
isLatestProposePlan?: boolean;
/** Whether this message is the latest propose_harness tool call (for external edit detection) */
isLatestProposeHarness?: boolean;
/** Optional bash_output grouping info (computed at render-time) */
bashOutputGroup?: BashOutputGroupInfo;
/** Navigation info for user messages (backward/forward between user messages) */
Expand All @@ -40,6 +42,7 @@ export const MessageRenderer = React.memo<MessageRendererProps>(
isCompacting,
onReviewNote,
isLatestProposePlan,
isLatestProposeHarness,
bashOutputGroup,
userMessageNavigation,
}) => {
Expand Down Expand Up @@ -72,6 +75,7 @@ export const MessageRenderer = React.memo<MessageRendererProps>(
workspaceId={workspaceId}
onReviewNote={onReviewNote}
isLatestProposePlan={isLatestProposePlan}
isLatestProposeHarness={isLatestProposeHarness}
bashOutputGroup={bashOutputGroup}
/>
);
Expand Down
13 changes: 11 additions & 2 deletions src/browser/components/Messages/ToolMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface ToolMessageProps {
onReviewNote?: (data: ReviewNoteData) => void;
/** Whether this is the latest propose_plan in the conversation */
isLatestProposePlan?: boolean;
/** Whether this is the latest propose_harness in the conversation */
isLatestProposeHarness?: boolean;
/** Optional bash_output grouping info */
bashOutputGroup?: BashOutputGroupInfo;
}
Expand All @@ -27,6 +29,7 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
workspaceId,
onReviewNote,
isLatestProposePlan,
isLatestProposeHarness,
bashOutputGroup,
}) => {
const { toolName, args, result, status, toolCallId } = message;
Expand All @@ -40,6 +43,12 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
? bashOutputGroup.position
: undefined;

const isLatest =
toolName === "propose_plan"
? isLatestProposePlan
: toolName === "propose_harness"
? isLatestProposeHarness
: undefined;
// Extract hook output if present (only shown when hook produced output)
const hookOutput = extractHookOutput(result);
const hookDuration = extractHookDuration(result);
Expand All @@ -59,8 +68,8 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
startedAt={message.timestamp}
// FileEdit-specific
onReviewNote={onReviewNote}
// ProposePlan-specific
isLatest={isLatestProposePlan}
// ProposePlan/ProposeHarness-specific
isLatest={isLatest}
// BashOutput-specific
groupPosition={groupPosition}
// CodeExecution-specific
Expand Down
Loading
Loading