Skip to content
Back to skills

Lang Roc Library Dev

ASecurity

Roc-specific library and platform development patterns. Use when creating reusable Roc packages, developing custom platforms, organizing package modules, exposing public APIs, managing platform interfaces, or publishing packages. Extends meta-library-dev with Roc's unique platform system and module patterns.

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added February 8, 2026
developmentrustgoexpresstestinggitapidocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add aRustyDev/ai --skill lang-roc-library-dev --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lang Roc Library Dev?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Lang Roc Library Dev
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/arustydev-lang-roc-library-dev/badge)](https://www.skillsdirectory.com/skills/arustydev-lang-roc-library-dev)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: lang-roc-library-dev
description: Roc-specific library and platform development patterns. Use when creating reusable Roc packages, developing custom platforms, organizing package modules, exposing public APIs, managing platform interfaces, or publishing packages. Extends meta-library-dev with Roc's unique platform system and module patterns.
created: 2025-12-28T22:00
updated: 2025-12-28T22:00
tags: [lang, roc, library, dev]
source: arustydev/ai
---

# Roc Library Development

Roc-specific patterns for library package and platform development. This skill extends `meta-library-dev` with Roc's unique platform architecture, package system, and module organization.

## This Skill Extends

- `meta-library-dev` - Foundational library patterns (API design, versioning, testing strategies)

For general concepts like semantic versioning, module organization principles, and testing pyramids, see the meta-skill first.

## This Skill Adds

- **Roc platform system**: Platform development, app/platform separation, I/O interfaces
- **Package organization**: Module structure, package declarations, visibility patterns
- **Roc idioms**: Pure functional patterns, platform interfaces, type inference
- **Roc ecosystem**: Standard library modules, builtin modules, platform conventions

## This Skill Does NOT Cover

- General library patterns - see `meta-library-dev`
- Roc application development - focus is on reusable packages/platforms
- Roc-specific syntax basics - see language documentation
- CLI application development - see CLI-specific skills

---

## Overview

Roc has a unique architecture that separates applications from platforms:

```
┌─────────────────────────────────────────────────────────────────┐
│                    Roc Package Architecture                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────┐                                              │
│  │  Application  │  (your code)                                 │
│  │    (.roc)     │                                              │
│  └───────┬───────┘                                              │
│          │                                                      │
│          │ imports                                              │
│          ▼                                                      │
│  ┌───────────────┐                                              │
│  │    Package    │  (reusable modules)                          │
│  │  package {}   │                                              │
│  └───────┬───────┘                                              │
│          │                                                      │
│          │ depends on                                           │
│          ▼                                                      │
│  ┌───────────────┐         ┌──────────────┐                    │
│  │   Platform    │────────▶│  Runtime     │                    │
│  │  platform {}  │         │  (Rust, C)   │                    │
│  └───────────────┘         └──────────────┘                    │
│          │                                                      │
│          └─ Provides I/O primitives (no I/O in stdlib)         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

**Key Concepts:**

| Concept | Purpose | I/O Allowed |
|---------|---------|-------------|
| **Package** | Reusable modules (pure functions/types) | No |
| **Platform** | Runtime + I/O primitives | Yes |
| **App** | Executable application | Yes (via platform) |
| **Module** | Single .roc file with exports | No (unless platform) |

**This skill focuses on creating Packages and Platforms for reuse.**

---

## Quick Reference

### File Types

| Type | Declaration | Purpose |
|------|-------------|---------|
| `app` | `app [main] { ... }` | Executable application |
| `package` | `package [Module1, Module2] { ... }` | Reusable package |
| `platform` | `platform "name" requires {} exposes {} packages {} ...` | Platform for apps |
| `module` | `module [export1, export2]` | Single module file |

### Common Commands

| Command | Description |
|---------|-------------|
| `roc check` | Type-check without building |
| `roc build` | Build executable |
| `roc test` | Run tests |
| `roc format` | Format code |
| `roc docs` | Generate documentation |

---

## Package Development

### Package Structure

```
my-package/
├── package/
│   ├── main.roc           # Package entry point
│   ├── Parser.roc         # Module files
│   ├── Types.roc
│   └── Internal.roc
├── examples/
│   └── basic.roc          # Example apps
├── platform/              # Optional: custom platform
│   └── main.roc
└── README.md
```

### Package Declaration

**package/main.roc:**
```roc
package [
    # Public modules (exposed to users)
    Parser,
    Types,
    # Can also expose specific values
    parseConfig,
    defaultConfig,
]
```

**Key Principles:**
1. Only expose what users need (minimal public API)
2. Keep implementation modules private
3. Re-export common types/functions at package level
4. Use descriptive module names

### Module Structure

**package/Parser.roc:**
```roc
module [
    # Public API
    parse,
    parseWithConfig,
    Config,
    ParseError,
]

import Types exposing [Document, Metadata]
import Internal  # Private import, not exposed

## Parse a document string.
##
## ```roc
## result = parse "# Title\nContent"
## expect result == Ok { title: "Title", content: "Content" }
## ```
parse : Str -> Result Document ParseError
parse = \input ->
    parseWithConfig input defaultConfig

## Configuration for parsing.
Config : {
    strict : Bool,
    preserveWhitespace : Bool,
}

defaultConfig : Config
defaultConfig = {
    strict: Bool.false,
    preserveWhitespace: Bool.false,
}

## Parse with custom configuration.
parseWithConfig : Str, Config -> Result Document ParseError
parseWithConfig = \input, config ->
    # Implementation
    # ...
```

### Visibility Patterns

**Module-level visibility:**
```roc
module [
    # Public: Anyone importing this module can use these
    publicFunction,
    PublicType,
]

# Private: Only visible within this module
privateHelper : Str -> Str
privateHelper = \x -> x

# Public functions can call private helpers
publicFunction : Str -> Str
publicFunction = \input ->
    privateHelper input
```

**Package-level visibility:**
```roc
# main.roc
package [
    # These modules are visible to package users
    Parser,
    Types,
]

# Internal is NOT in package exports = private to package
import Internal
```

---

## Platform Development

### Platform Structure

```
my-platform/
├── platform/
│   └── main.roc           # Platform declaration
├── host/
│   ├── Cargo.toml         # Rust host implementation
│   └── src/
│       ├── lib.rs
│       └── main.rs
└── examples/
    └── hello.roc
```

### Platform Declaration

**platform/main.roc:**
```roc
platform "cli"
    requires { Model } { main : Task Model [] }
    exposes [
        Task,
        Stdout,
        Stdin,
        File,
        Path,
        Env,
    ]
    packages {}
    imports []
    provides [mainForHost]

import Task
import Internal.Task

mainForHost : Task.Task Model [] as Fx
mainForHost = main
```

**Key Components:**

| Section | Purpose |
|---------|---------|
| `requires` | What apps must provide (e.g., `main` function) |
| `exposes` | Modules the platform provides to apps |
| `packages` | Dependencies |
| `imports` | Internal platform imports |
| `provides` | Entry point for host |

### Platform Interface Design

**Good platform design:**

1. **Clear separation of concerns:**
```roc
# Platform exposes pure types and Task-based I/O
module [
    # Pure types
    Request,
    Response,
    # Effectful operations
    serveHttp : Config, (Request -> Task Response []) -> Task {} []
]
```

2. **Type-safe I/O:**
```roc
# File module
read : Path -> Task Str [FileNotFound, PermissionDenied]
write : Path, Str -> Task {} [PermissionDenied, DiskFull]

# Stdin module
line : Task Str [EndOfInput]
```

3. **Composable effects:**
```roc
# Tasks can be chained
program : Task {} []
program =
    path <- Task.await (Env.var "CONFIG_PATH")
    contents <- Task.await (File.read path)
    config <- Task.await (parseConfig contents)
    runServer config
```

---

## Module Organization Patterns

### Single Responsibility Modules

```roc
# Types.roc - Just type definitions
module [Config, Document, Metadata]

Config : {
    timeout : U64,
    retries : U8,
}

Document : {
    title : Str,
    content : Str,
    metadata : Metadata,
}

Metadata : {
    author : Str,
    created : U64,
}
```

### Extension Modules

```roc
# ConfigExt.roc - Operations on Config
module [default, withTimeout, validate]

import Types exposing [Config]

default : Config
default = {
    timeout: 30_000,
    retries: 3,
}

withTimeout : Config, U64 -> Config
withTimeout = \config, ms -> { config & timeout: ms }

validate : Config -> Result Config [InvalidTimeout, InvalidRetries]
validate = \config ->
    if config.timeout == 0 then
        Err InvalidTimeout
    else if config.retries > 10 then
        Err InvalidRetries
    else
        Ok config
```

### Re-export Pattern

**package/main.roc:**
```roc
package [
    # Re-export commonly used types from multiple modules
    Config,
    Document,
    # Re-export main functions
    parse,
    parseWithConfig,
    # Expose modules for advanced usage
    Parser,
    Types,
]

# Import everything needed for re-exports
import Parser exposing [parse, parseWithConfig]
import Types exposing [Config, Document]
```

---

## Type Design Patterns

### Opaque Types

```roc
module [UserId, fromU64, toU64]

# Opaque: internals hidden from users
UserId := U64

## Create a UserId from a U64.
fromU64 : U64 -> UserId
fromU64 = @UserId

## Extract the U64 from a UserId.
toU64 : UserId -> U64
toU64 = \@UserId id -> id
```

### Tagged Unions for Errors

```roc
module [ParseError, toStr]

ParseError : [
    InvalidSyntax Str,
    UnexpectedEnd,
    UnknownTag Str,
]

toStr : ParseError -> Str
toStr = \err ->
    when err is
        InvalidSyntax msg -> "Invalid syntax: $(msg)"
        UnexpectedEnd -> "Unexpected end of input"
        UnknownTag tag -> "Unknown tag: $(tag)"
```

### Builder Pattern (Records with Defaults)

```roc
module [Config, default, build, withTimeout, withRetries]

Config : {
    timeout : U64,
    retries : U8,
    strict : Bool,
}

default : Config
default = {
    timeout: 30_000,
    retries: 3,
    strict: Bool.false,
}

build : {} -> Config
build = \{} -> default

withTimeout : Config, U64 -> Config
withTimeout = \config, ms -> { config & timeout: ms }

withRetries : Config, U8 -> Config
withRetries = \config, n -> { config & retries: n }

# Usage:
# config = build {} |> withTimeout 60_000 |> withRetries 5
```

---

## Testing Patterns

### Expect Blocks

```roc
## Parse a valid document.
parse : Str -> Result Document ParseError
parse = \input ->
    # Implementation
    # ...

# Test cases using expect
expect
    result = parse "# Title\nContent"
    result == Ok { title: "Title", content: "Content" }

expect
    result = parse ""
    result == Err UnexpectedEnd

expect
    result = parse "# Title\nContent"
    Result.isOk result
```

### Test Modules

**tests/ParserTests.roc:**
```roc
module []

import Parser exposing [parse, ParseError]

expect
    # Happy path
    input = "# Hello\nWorld"
    result = parse input
    result == Ok { title: "Hello", content: "World" }

expect
    # Error case
    result = parse ""
    result == Err UnexpectedEnd

expect
    # Edge case
    input = Str.repeat "a" 10_000
    result = parse input
    Result.isOk result
```

### Property-Based Testing Pattern

```roc
# Generate test cases
expectAll = \cases ->
    List.all cases \case ->
        expected = case.expected
        actual = parse case.input
        actual == expected

expect
    cases = [
        { input: "# A\nB", expected: Ok { title: "A", content: "B" } },
        { input: "", expected: Err UnexpectedEnd },
        { input: "###", expected: Err (InvalidSyntax "Too many #") },
    ]
    expectAll cases
```

---

## Builtin Modules

Roc provides several builtin modules auto-imported into every file:

| Module | Purpose | Common Functions |
|--------|---------|------------------|
| `Str` | String operations | `concat`, `split`, `trim`, `to_utf8` |
| `Num` | Numeric operations | `add`, `sub`, `is_even`, `abs` |
| `List` | List operations | `map`, `filter`, `fold_left`, `len` |
| `Dict` | Dictionary/Map | `insert`, `get`, `keys`, `values` |
| `Set` | Set operations | `insert`, `contains`, `union` |
| `Bool` | Boolean operations | `true`, `false`, `not` |
| `Result` | Result type | `Ok`, `Err`, `map`, `try` |

**Note:** The standard library provides NO I/O operations. All I/O comes from platforms.

---

## Breaking Changes (2025)

### Snake Case Migration

Builtins are migrating from `camelCase` to `snake_case`:

```roc
# Old (deprecated)
Str.joinWith
List.keepIf

# New (current)
Str.join_with
List.keep_if
```

**Action:** Use new snake_case names in all new packages.

### Task Deprecation (Purity Inference)

`Task` is deprecated in favor of purity inference:

```roc
# Old pattern
readConfig : Task Config [FileNotFound]
readConfig =
    path <- Task.await (Env.var "CONFIG")
    contents <- Task.await (File.read path)
    Task.ok (parse contents)

# New pattern (purity inferred)
readConfig : Config ![FileNotFound, EnvVarNotSet]
readConfig =
    path = Env.var! "CONFIG"
    contents = File.read! path
    parse contents
```

**Action:** For new platforms, use purity inference. For compatibility, check platform docs.

---

## Publishing Packages

### Pre-publish Checklist

- [ ] `roc check` passes on all modules
- [ ] `roc test` passes
- [ ] `roc format` applied to all files
- [ ] Documentation comments on all public functions
- [ ] Examples in `examples/` directory
- [ ] README.md with usage examples
- [ ] Version follows semantic versioning
- [ ] No dependencies on unreleased packages
- [ ] License file included

### Package Metadata

**Include in README.md:**

```markdown
# My Package

Brief description of what this package does.

## Installation

How to include this package in a Roc project.

## Quick Start

\```roc
import MyPackage exposing [parse]

main =
    result = parse "input"
    # ...
\```

## Modules

- `Parser` - Main parsing logic
- `Types` - Type definitions
- `Config` - Configuration utilities

## Examples

See `examples/` directory.

## License

MIT
```

---

## Common Patterns

### Error Handling

```roc
# Return Result for operations that can fail
parse : Str -> Result Document [InvalidSyntax Str, UnexpectedEnd]
parse = \input ->
    if Str.is_empty input then
        Err UnexpectedEnd
    else
        # Parse logic
        Ok document

# Chain Results
processDocument : Str -> Result ProcessedDoc [ParseError, ValidationError]
processDocument = \input ->
    parsed <- Result.try (parse input |> Result.map_err ParseError)
    validated <- Result.try (validate parsed |> Result.map_err ValidationError)
    Ok (process validated)
```

### Polymorphic Functions

```roc
# Generic over any type
identity : a -> a
identity = \x -> x

# Constrained generics (via abilities - future feature)
compare : a, a -> [LT, EQ, GT] where a implements Ord
```

### Pipeline Pattern

```roc
# Use |> for readable data transformations
processData : List Str -> List Str
processData = \items ->
    items
    |> List.map Str.trim
    |> List.keep_if (\s -> !(Str.is_empty s))
    |> List.map Str.to_lowercase
    |> List.sort_with Str.compare
```

---

## Anti-Patterns

### 1. Leaking Implementation Details

```roc
# Bad: Exposing internal structure
module [Config, InternalState]

# Good: Only expose what's needed
module [Config, fromStr, toStr]
```

### 2. Overly Large Modules

```roc
# Bad: Single module with 1000+ lines

# Good: Split into focused modules
# - Types.roc (types)
# - Parser.roc (parsing)
# - Validator.roc (validation)
# - main.roc (re-exports)
```

### 3. Missing Documentation

```roc
# Bad: No docs
parse : Str -> Result Document ParseError

# Good: Documented
## Parse a document from a string.
##
## Returns a Document on success, or ParseError if the input is invalid.
##
## ```roc
## result = parse "# Title"
## expect result == Ok { title: "Title", ... }
## ```
parse : Str -> Result Document ParseError
```

### 4. Platform Doing Too Much

```roc
# Bad: Platform provides complex business logic
module [
    readUserFromDb,
    validateUser,
    sendEmail,
]

# Good: Platform provides primitives
module [
    dbQuery,
    httpRequest,
    # Let apps compose these into business logic
]
```

---

## Troubleshooting

### Module Not Found

**Symptom:** `Module 'MyModule' not found`

**Causes & Fixes:**

| Cause | Fix |
|-------|-----|
| Module not in package exports | Add to `package [...]` list |
| File name doesn't match module | Rename file to match (e.g., `MyModule.roc`) |
| Import path incorrect | Use correct relative/absolute path |

### Type Inference Failures

**Symptom:** `Cannot infer type for this expression`

**Fixes:**
1. Add explicit type annotation
2. Provide more context (often happens in empty lists)
3. Check for ambiguous number types (add `U64`, `I32`, etc.)

```roc
# Problem: Ambiguous type
nums = []

# Fix: Provide type context
nums : List U64
nums = []

# Or use in context
nums = List.range { start: At 1, end: At 10 }
```

### Circular Dependencies

**Symptom:** `Circular dependency detected`

**Fix:** Restructure modules

```roc
# Before (circular):
# A.roc imports B.roc
# B.roc imports A.roc

# After: Extract shared types
# Types.roc (shared types)
# A.roc imports Types
# B.roc imports Types
```

---

## Platform Examples

### Basic CLI Platform

```roc
platform "basic-cli"
    requires { Model } { main : Task Model [] }
    exposes [
        Task,
        Stdout,
        Stdin,
        File,
        Path,
        Env,
        Arg,
    ]
    packages {}
    imports []
    provides [mainForHost]

mainForHost : Task Model [] as Fx
mainForHost = main
```

### Web Platform

```roc
platform "basic-webserver"
    requires {} { main : Request -> Task Response [] }
    exposes [
        Request,
        Response,
        Task,
        Stdout,
    ]
    packages {}
    imports []
    provides [mainForHost]

Request : {
    method : [GET, POST, PUT, DELETE],
    url : Str,
    headers : Dict Str Str,
    body : List U8,
}

Response : {
    status : U16,
    headers : Dict Str Str,
    body : List U8,
}
```

---

## References

- `meta-library-dev` - Foundational library patterns
- [Roc Tutorial](https://www.roc-lang.org/tutorial)
- [Roc Platforms](https://www.roc-lang.org/platforms)
- [GitHub - roc-lang/roc](https://github.com/roc-lang/roc)
- [basic-cli Platform](https://github.com/roc-lang/basic-cli)
- [basic-webserver Platform](https://github.com/roc-lang/basic-webserver)

---

## Sources

- [The Roc Programming Language](https://www.roc-lang.org/)
- [GitHub - roc-lang/roc](https://github.com/roc-lang/roc)
- [Tutorial | Roc](https://www.roc-lang.org/tutorial)
- [Platforms and Apps | Roc](https://www.roc-lang.org/platforms)
- [Understanding Roc: Functional and separate from the runtime | TechTarget](https://www.techtarget.com/searchapparchitecture/tip/Understanding-Roc-Functional-and-separate-from-the-runtime)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…