Architecture
Joy's internal architecture - crate structure, data model, status workflow, and configuration.
Crate Structure
Joy is implemented in Rust as a set of crates within the joyint/joy repository. The joy-core library crate contains the shared logic, while joy-cli and joy-ai are binary and library crates that depend on it.
What joy-core Provides
| Module | Purpose |
|---|---|
| Item model | Types, priorities, effort, tags, dependencies, parent-child relationships |
| YAML I/O | Read and write .joy/ files with validation |
| Status logic | State machine for item lifecycle |
| Event log | Append-only log of all actions for audit |
| Config system | Layered configuration with defaults, project, and personal overrides |
| Git integration | Commit detection, branch awareness, VCS abstraction |
Data Model
The data model centers on the project, its items, and its milestones. A workspace is a conceptual grouping (a data container backed by a Git repo), not a stored entity, so it does not appear below.
An item can also reference other items directly: parent points to a parent item (epic or story), and deps lists items that must be done first. Both are item-to-item links and are not drawn as separate entities below.
Item Types
Every item has a type that describes what kind of work it represents:
| Type | Purpose |
|---|---|
| epic | Large body of work, contains child items |
| story | User-facing feature or change |
| task | Technical work, implementation step |
| bug | Defect to fix |
| rework | Improvement to existing code (refactor, cleanup) |
| decision | Architectural or process decision to document |
| idea | Captured thought, not yet committed to |
Priority and Effort
Priority levels: critical, high, medium, low.
Effort uses a 1-7 scale: 1 = trivial, 2 = small, 3 = medium, 4 = large, 5 = major, 6 = heavy, 7 = massive.
Status Workflow
Items follow a small, defined lifecycle (new, open, in-progress, review, closed, deferred) with one-word verb shortcuts, and transitions can be tightened with gates. See the Workflow page for the states, verbs, gates, and the full diagram.
Config Layering
Joy uses a layered configuration system. Each layer overrides the previous one, so project settings can override defaults, and personal preferences can override project settings.
How Layering Works
- Code defaults - Hard-coded values in
joy-core. Always present, always reasonable. - config.defaults.yaml - Shipped with Joy in
.joy/, defines the default configuration values. - Global config - User-level settings in
~/.config/joy/config.yaml. Apply to every project. - Project config - Project-local settings in
.joy/config.yaml, committed so the whole team shares them.
Each layer only needs to specify the values it wants to override. Everything else falls through to the layer below.