with one click
with one click
Run OpenWork UI evals on a Daytona sandbox or local Electron instance. Handles sandbox creation, service startup, and eval execution via CDP browser tools.
Guide users through browser automation setup using Chrome DevTools MCP only. Use when the user asks to set up browser automation, Chrome DevTools MCP, browser MCP, or runs the browser-setup command.
Manages Cargo.lock file updates and resolves --locked flag issues in CI/CD. Triggers when user mentions: - "cargo test --locked failed" - "cannot update the lock file" - "Cargo.lock is out of date" - "PR failed with --locked error" - "fix Cargo.lock"
Publish the openwork-orchestrator npm package with clean git hygiene. Triggers when user mentions: - "openwork-orchestrator npm publish" - "publish openwork-orchestrator" - "bump openwork-orchestrator"
Debug OpenWork sidecars, config, and audit trail
Core context and guardrails for OpenWork native app
| name | solidjs-patterns |
| description | SolidJS reactivity + UI state patterns for OpenWork |
OpenWork’s UI is SolidJS: it updates via signals, not React-style rerenders.
Most “UI stuck” bugs are actually state coupling bugs (e.g. one global busy() disabling an unrelated action), not rerender issues.
This skill captures the patterns we want to consistently use in OpenWork.
pending state).createMemo() instead of duplicating booleans.When an operation can overlap with others (permissions, installs, background refresh), don’t reuse a global busy().
Use a dedicated signal per action:
const [replying, setReplying] = createSignal(false);
async function respond() {
if (replying()) return;
setReplying(true);
try {
await doTheThing();
} finally {
setReplying(false);
}
}
A single busy() boolean creates deadlocks:
busy(true)busy()Fix: permission UI must be disabled only by a permission-specific pending state.
If you read signals inside an async function and you need stable values, snapshot early:
const request = activePermission();
if (!request) return;
const requestID = request.id;
await respondPermission(requestID, "always");
Prefer createMemo() for computed disabled states:
const canSend = createMemo(() => prompt().trim().length > 0 && !busy());
setItems((current) => current.filter((x) => x.id !== id));
current in-place.await where values might have changed?