better-result-adopt
Migrate codebase from try/catch or Promise-based error handling to better-result. Use when adopting Result types, converting thrown exceptions to typed errors, or refactoring existing error handling to railway-oriented programming.
Best use case
better-result-adopt is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Migrate codebase from try/catch or Promise-based error handling to better-result. Use when adopting Result types, converting thrown exceptions to typed errors, or refactoring existing error handling to railway-oriented programming.
Teams using better-result-adopt should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/adopt/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How better-result-adopt Compares
| Feature / Agent | better-result-adopt | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Migrate codebase from try/catch or Promise-based error handling to better-result. Use when adopting Result types, converting thrown exceptions to typed errors, or refactoring existing error handling to railway-oriented programming.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
AI Agents for Coding
Browse AI agent skills for coding, debugging, testing, refactoring, code review, and developer workflows across Claude, Cursor, and Codex.
Best AI Skills for Claude
Explore the best AI skills for Claude and Claude Code across coding, research, workflow automation, documentation, and agent operations.
Cursor vs Codex for AI Workflows
Compare Cursor and Codex for AI coding workflows, repository assistance, debugging, refactoring, and reusable developer skills.
SKILL.md Source
# better-result Adoption
Migrate existing error handling (try/catch, Promise rejections, thrown exceptions) to typed Result-based error handling with better-result.
## When to Use
- Adopting better-result in existing codebase
- Converting try/catch blocks to Result types
- Replacing thrown exceptions with typed errors
- Migrating Promise-based code to Result.tryPromise
- Introducing railway-oriented programming patterns
## Migration Strategy
### 1. Start at Boundaries
Begin migration at I/O boundaries (API calls, DB queries, file ops) and work inward. Don't attempt full-codebase migration at once.
### 2. Identify Error Categories
Before migrating, categorize errors in target code:
| Category | Example | Migration Target |
| -------------- | ---------------------- | ----------------------------------------------- |
| Domain errors | NotFound, Validation | TaggedError + Result.err |
| Infrastructure | Network, DB connection | Result.tryPromise + TaggedError |
| Bugs/defects | null deref, type error | Let throw (becomes Panic if in Result callback) |
### 3. Migration Order
1. Define TaggedError classes for domain errors
2. Wrap throwing functions with Result.try/tryPromise
3. Convert imperative error checks to Result chains
4. Refactor callbacks to generator composition
## Pattern Transformations
### Try/Catch to Result.try
```typescript
// BEFORE
function parseConfig(json: string): Config {
try {
return JSON.parse(json);
} catch (e) {
throw new ParseError(e);
}
}
// AFTER
function parseConfig(json: string): Result<Config, ParseError> {
return Result.try({
try: () => JSON.parse(json) as Config,
catch: (e) => new ParseError({ cause: e, message: `Parse failed: ${e}` }),
});
}
```
### Async/Await to Result.tryPromise
```typescript
// BEFORE
async function fetchUser(id: string): Promise<User> {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new ApiError(res.status);
return res.json();
}
// AFTER
async function fetchUser(id: string): Promise<Result<User, ApiError | UnhandledException>> {
return Result.tryPromise({
try: async () => {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new ApiError({ status: res.status, message: `API ${res.status}` });
return res.json() as Promise<User>;
},
catch: (e) => (e instanceof ApiError ? e : new UnhandledException({ cause: e })),
});
}
```
### Null Checks to Result
```typescript
// BEFORE
function findUser(id: string): User | null {
return users.find((u) => u.id === id) ?? null;
}
// Caller must check: if (user === null) ...
// AFTER
function findUser(id: string): Result<User, NotFoundError> {
const user = users.find((u) => u.id === id);
return user
? Result.ok(user)
: Result.err(new NotFoundError({ id, message: `User ${id} not found` }));
}
// Caller: yield* findUser(id) in Result.gen, or .match()
```
### Callback Hell to Generator
```typescript
// BEFORE
async function processOrder(orderId: string) {
try {
const order = await fetchOrder(orderId);
if (!order) throw new NotFoundError(orderId);
const validated = validateOrder(order);
if (!validated.ok) throw new ValidationError(validated.errors);
const result = await submitOrder(validated.data);
return result;
} catch (e) {
if (e instanceof NotFoundError) return { error: "not_found" };
if (e instanceof ValidationError) return { error: "invalid" };
throw e;
}
}
// AFTER
async function processOrder(orderId: string): Promise<Result<OrderResult, OrderError>> {
return Result.gen(async function* () {
const order = yield* Result.await(fetchOrder(orderId));
const validated = yield* validateOrder(order);
const result = yield* Result.await(submitOrder(validated));
return Result.ok(result);
});
}
// Error type is union of all yielded errors
```
## Defining TaggedErrors
See [references/tagged-errors.md](references/tagged-errors.md) for TaggedError patterns.
## Workflow
1. **Check for source reference**: Look for `opensrc/` directory - if present, read the better-result source code for implementation details and patterns
2. **Audit**: Find try/catch, Promise.catch, thrown errors in target module
3. **Define errors**: Create TaggedError classes for domain errors
4. **Wrap boundaries**: Use Result.try/tryPromise at I/O points
5. **Chain operations**: Convert if/else error checks to .andThen or Result.gen
6. **Update signatures**: Change return types to Result<T, E>
7. **Update callers**: Propagate Result handling up call stack
8. **Test**: Verify error paths with .match or type narrowing
## Common Pitfalls
- **Over-wrapping**: Don't wrap every function. Start at boundaries, propagate inward.
- **Losing error info**: Always include cause/context in TaggedError constructors.
- **Mixing paradigms**: Once a module returns Result, callers should too (or explicitly .unwrap).
- **Ignoring Panic**: Callbacks that throw become Panic. Fix the bug, don't catch Panic.
## References
- [TaggedError Patterns](references/tagged-errors.md) - Defining and matching typed errors
- `opensrc/` directory (if present) - Full better-result source code for deeper contextRelated Skills
better-result-migrate-v2
Migrate better-result TaggedError from v1 (class-based) to v2 (factory-based) API
better-auth-best-practices
Skill for integrating Better Auth - the comprehensive TypeScript authentication framework.
result-to-claim
Use when experiments complete to judge what claims the results support, what they don't, and what evidence is still missing. Codex MCP evaluates results against intended claims and routes to next action (pivot, supplement, or confirm). Use after experiments finish — before writing the paper or running ablations.
analyze-results
Analyze ML experiment results, compute statistics, generate comparison tables and insights. Use when user says "analyze results", "compare", or needs to interpret experimental data.
better-auth-best-practices
Configure Better Auth server and client, set up database adapters, manage sessions, add plugins, and handle environment variables. Use when users mention Better Auth, betterauth, auth.ts, or need to set up TypeScript authentication with email/password, OAuth, or plugin configuration.
Authentication (Better Auth)
**When to use:** Sessions, sign-in/sign-up flows, OAuth, magic links, or organization context on the session.
better-soul
Write powerful SOUL.md files for AI agents. Use when creating, revising, or improving SOUL.md (the personality document for AI agents). Based on Anthropic's Claude soul document principles and SoulSpec standard.
ai-adoption-readiness
Assess organizational readiness for AI adoption across 6 dimensions: culture, data maturity, tech stack, leadership buy-in, skills/talent, and process maturity. Generates a scored readiness report with gap analysis and a prioritized action plan. Use before building a change management plan to understand where an organization actually stands. Built by AfrexAI.
claude-better-cli
Compatibility-first Claude CLI reimplementation with faster startup, lower memory, and drop-in command compatibility
better-auth-best-practices
Skill for integrating Better Auth - the comprehensive TypeScript authentication framework.
bio-de-results
Extract, filter, annotate, and export differential expression results from DESeq2 or edgeR. Use for identifying significant genes, applying multiple testing corrections, adding gene annotations, and preparing results for downstream analysis. Use when filtering and exporting DE analysis results.
nuxt-better-auth
Use when implementing auth in Nuxt apps with @onmax/nuxt-better-auth - provides useUserSession composable, server auth helpers, route protection, and Better Auth plugins integration.