Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
],
"features": {
"ghcr.io/devcontainers/features/nix:1": {
"packages": [] // home-manager handles packages
"packages": [] // home-manager handles packages, like direnv
}
},
"secrets": {
Expand Down
6 changes: 6 additions & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Summary

- [Git: Step Zero](./chapter_1.md)
- [Devcontainers](./chapter_2.md)
- [Nix](./nix/README.md)
- [Home Manager](./nix/home-manager.md)
- [Flakes]()
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Flakes entry has an empty link target, which will result in a broken link in the generated documentation. Either provide the actual path to the Flakes documentation file, or remove this entry until the documentation is ready.

Suggested change
- [Flakes]()

Copilot uses AI. Check for mistakes.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeholder to denote flakes are not forgotten but not implemented/documented yet

- [Tools](./tools/README.md)
- [Just](./tools/just.md)
3 changes: 2 additions & 1 deletion book/src/chapter_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Git needs no introduction—it's the ubiquitous version control system you alrea

## The Initial Commit

This repository started with a single commit ([821861c](https://github.com/alyssa-e/dev/commit/821861c9bc14679aa12fd1b7c8833219ce0a1616)) containing only a `.gitignore`:
This repository started with a single commit ([821861c](https://github.com/alycda/dev/commit/821861c9bc14679aa12fd1b7c8833219ce0a1616)) containing only a `.gitignore`:

```gitignore
# Ignore build outputs from performing a nix-build or `nix build` command
Expand Down Expand Up @@ -52,5 +52,6 @@ The specific patterns vary; the principle doesn't. Start clean, stay clean.

---

- https://learnxinyminutes.com/git/
- https://git-scm.com/docs/gitignore
- https://www.kernel.org/pub/software/scm/git/docs/gitignore.html
87 changes: 87 additions & 0 deletions book/src/chapter_2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Devcontainers

Devcontainers often get a bad reputation—and sometimes deservedly so. Running Docker for a simple webpage feels like swatting a fly with a sledgehammer, especially when the container is bloated and slow.

But the *idea* behind devcontainers is sound: **a reproducible, isolated development environment**.

## The Real Problem

It's not about Docker. It's about maintaining focus and productivity by keeping your working environment clean:

- VS Code extensions that conflict or clutter
- System binaries that drift between machines
- "Works on my machine" debugging sessions
- Configuration that accumulates like sediment

A devcontainer solves this by declaring exactly what your environment should contain—nothing more, nothing less.

> **macOS Users:** If you're developing locally, use [OrbStack](https://orbstack.dev/) instead of Docker Desktop. It's significantly faster, lighter on resources, and makes devcontainer iteration actually pleasant. The trial is generous enough to evaluate whether the speed gains justify the cost.

## Starting Minimal

This template's initial devcontainer ([cc11da7](https://github.com/alycda/dev/commit/cc11da7273691c76e44d6317dc5547561d078024)) was intentionally sparse:

```json
{
"image": "debian:bookworm-slim",
"features": {
"ghcr.io/devcontainers/features/nix:1": {
"packages": ["direnv"]
}
Comment on lines +27 to +30
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential documentation inconsistency. The chapter shows the initial setup with direnv in the Nix feature packages array, but the current devcontainer.json (line 8) indicates that direnv is now handled by home-manager. This evolution should be explicitly mentioned in the documentation to explain why the initial setup differs from the current state, or the example should be updated to match the current configuration.

Copilot uses AI. Check for mistakes.
},
"customizations": {
"vscode": {
"extensions": ["jnoortheen.nix-ide"],
"settings": {
"editor.wordWrap": "on",
"git.autofetch": true
}
}
}
}
```

That's it:
- **Debian slim** - A minimal base, not Ubuntu with kitchen sink
- **Nix + direnv** - The foundation for reproducible tooling (more on this later)
- **One extension** - Nix language support
- **Sensible defaults** - Word wrap, auto-fetch

## Why This Matters

The devcontainer is the *second* commit in this repository's history (after `.gitignore`). This ordering is intentional:

1. **Step 0**: Ignore the right files
2. **Step 1**: Define the environment

Everything else—the actual code, the tools, the configuration—builds on this foundation. When you open this repository in VS Code or GitHub Codespaces, you get exactly the environment the project expects.

## The Nix Connection

Notice that we install Nix immediately. The devcontainer itself stays minimal because Nix (via `shell.nix` and `direnv`) handles the actual development tools. This separation means:

- The container is fast to build
- Tools are managed declaratively in Nix
- You can use the same Nix configuration outside Docker

We'll cover Nix in detail in the next [chapter](./nix/README.md).

## When to Use Devcontainers

Use them when:
- **Onboarding matters** - New contributors should be productive in minutes
- **Environment consistency is critical** - CI/CD should match local dev
- **You're using Codespaces** - It's the native way to define the environment

Skip them when:
- The project is simple enough that a README suffices
- Docker overhead genuinely hurts your workflow
- You're the only developer and prefer native tooling

The goal isn't Docker for Docker's sake—it's having a single source of truth for "what does this project need to run?"

---

- https://learnxinyminutes.com/docker/
- https://containers.dev/
- https://code.visualstudio.com/docs/devcontainers/containers
90 changes: 90 additions & 0 deletions book/src/nix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Nix

Nix is a package manager that guarantees reproducibility. Same inputs, same outputs—every time, on every machine.

If you've ever dealt with "it works on my machine" or spent hours debugging environment differences, Nix solves that problem at the root.

## The Core Idea

Traditional package managers install software globally and hope for the best. Nix takes a different approach:

- **Immutable packages** - Each package is stored in isolation with a unique hash
- **Declarative configuration** - You describe *what* you want, not *how* to install it
- **Reproducible builds** - The same `shell.nix` produces the same environment everywhere

## The Initial Setup

This template's first Nix integration ([8b951a5](https://github.com/alycda/dev/commit/8b951a56c38efb96b6f7533d6b10a946b7d3c233)) added three files:

### shell.nix

```nix
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
buildInputs = with pkgs; [ just ];
}
```

This declares a shell environment with one tool: `just` (a command runner). Want more tools? Add them to the list:

```nix
buildInputs = with pkgs; [ just nodejs python3 rustc ];
```

### .envrc

```bash
use nix
```

This one-liner tells `direnv` to activate the Nix shell automatically when you enter the directory.

### The Hook

The devcontainer's `postCreateCommand` wires it together:

```bash
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && direnv allow
```

## How It Works

1. You `cd` into the project directory
2. `direnv` detects `.envrc`
3. `.envrc` says `use nix`
4. Nix builds/fetches the packages in `shell.nix`
5. Your shell now has those tools available

Leave the directory, tools disappear. Enter again, they're back. No global pollution.

## Why This Matters

The devcontainer installs Nix, but Nix manages the actual tools. This separation is powerful:

- **Lightweight container** - Just Debian + Nix, nothing else
- **Declarative tools** - `shell.nix` is version-controlled documentation of your dependencies
- **Works anywhere** - Same `shell.nix` works on macOS, Linux, or in Codespaces
- **Easy iteration** - Add a tool to `shell.nix`, run `direnv reload`, done

## Current State

The template's `shell.nix` has grown to include several tools:

```nix
buildInputs = with pkgs; [ just cheat asciinema_3 presenterm tmux mdbook ];
```

Each of these gets its own chapter later. The point is: adding tools is trivial. One line in `shell.nix`, and everyone who clones this repo gets the same environment.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states "Each of these gets its own chapter later" referring to the tools in shell.nix (just, cheat, asciinema, presenterm, tmux, mdbook), but none of these chapters appear in the SUMMARY.md. This creates an unfulfilled promise to readers. Consider either adding these chapters or removing this forward reference.

Suggested change
Each of these gets its own chapter later. The point is: adding tools is trivial. One line in `shell.nix`, and everyone who clones this repo gets the same environment.
Whether it's just one tool or many, adding them is trivial. One line in `shell.nix`, and everyone who clones this repo gets the same environment.

Copilot uses AI. Check for mistakes.

## Finding Packages

Search for packages at [search.nixos.org](https://search.nixos.org/packages). The repository has over 100,000 packages—if it exists, Nix probably has it.

---

- https://nixos.org/
- https://nix.dev/ (tutorials)
- https://direnv.net/
- https://learnxinyminutes.com/nix/
- https://nixcloud.io/tour/
118 changes: 118 additions & 0 deletions book/src/nix/home-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Nix: Home Manager

The previous chapter covered `shell.nix` for project-specific tools. But what about tools you want *everywhere*—your editor, your shell configuration, your personal utilities?

That's what [Home Manager](https://github.com/nix-community/home-manager) solves.

## shell.nix vs home.nix

Think of it this way:

| | shell.nix | home.nix |
|---|---|---|
| **Scope** | Per-project | Per-user |
| **Activates** | When you `cd` into directory | Always available |
| **Use for** | Project dependencies | Personal tools and config |

`shell.nix` gives you `just` and `mdbook` when working on this template. `home.nix` gives you `helix` and `ripgrep` no matter what directory you're in.

## The Initial Setup

Home Manager was introduced in commit [c8ec56a](https://github.com/alycda/dev/commit/c8ec56a009f579f012a17566f5862dd2bd42cd81):

```nix
{ pkgs, ... }:
{
programs.home-manager.enable = true;

home.packages = with pkgs; [
helix
ripgrep
];

programs.direnv = {
enable = true;
nix-direnv.enable = true;
};

home.stateVersion = "24.05";
home.username = "root";
home.homeDirectory = "/root";
}
```

This declares:
- **Core packages** - `helix` (editor) and `ripgrep` (search) available globally
- **direnv integration** - With `nix-direnv` for faster Nix shell loading
- **Self-management** - Home Manager can update itself

## Beyond Packages

Home Manager doesn't just install tools—it *configures* them. The current `home.nix` includes:

```nix
home.sessionVariables = {
EDITOR = "hx";
VISUAL = "code";
};

programs.bash = {
enable = true;
initExtra = ''
# Custom shell initialization
'';
};
```

Your editor preferences, shell configuration, environment variables—all declarative, all version-controlled.

## The Rebuild Command

When you modify `home.nix`, apply changes with:

```bash
just rebuild
```

Which runs:

```bash
home-manager switch -b backup -f .devcontainer/home.nix
```

The `-b backup` flag preserves any existing dotfiles that would be overwritten.

## Current State

The template's `home.nix` has grown to include:

```nix
home.packages = with pkgs; [
helix # Terminal editor
ripgrep # Fast search
jujutsu # Git-compatible VCS
gh # GitHub CLI
claude-code # AI assistant
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package name "claude-code" may not be a standard Nix package. Claude is typically accessed via API or web interface, not as a standalone installable package. Verify that this package exists in nixpkgs or clarify if this is a custom package. If it doesn't exist, this could cause build failures when users try to apply this configuration.

Suggested change
claude-code # AI assistant
fd # Fast file finder

Copilot uses AI. Check for mistakes.
];
```

Each tool is available immediately in any new shell, not just project directories.

## Why Two Layers?

This separation—`shell.nix` for projects, `home.nix` for user—mirrors how you actually work:

1. **Personal tools** (editor, shell, utilities) follow you everywhere
2. **Project tools** (build systems, language toolchains) activate per-project

A Node.js project needs `nodejs` in its `shell.nix`. But you want `helix` and `ripgrep` regardless of what project you're in.

## Up Next: Just

You've seen `just rebuild` above. The [next chapter](./tools/just.md) covers Just—a command runner that ties these tools together with simple, memorable commands.
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The relative path in this link is incorrect. Since this file is located at book/src/nix/home-manager.md, the path "./tools/just.md" tries to find tools/ inside the nix/ directory. The correct relative path should be "../tools/just.md" to navigate up to the src directory, then into the tools directory.

Suggested change
You've seen `just rebuild` above. The [next chapter](./tools/just.md) covers Just—a command runner that ties these tools together with simple, memorable commands.
You've seen `just rebuild` above. The [next chapter](../tools/just.md) covers Just—a command runner that ties these tools together with simple, memorable commands.

Copilot uses AI. Check for mistakes.

---

- https://github.com/nix-community/home-manager
- https://nix-community.github.io/home-manager/
- https://home-manager-options.extranix.com/
14 changes: 14 additions & 0 deletions book/src/tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Tools

This section covers the tools included in this template's `shell.nix`. They're available automatically when you enter the project directory thanks to direnv.

These aren't arbitrary choices—each solves a specific friction point in development workflows:

- **Just** - Command runner for memorable aliases
- **cheat** - Quick reference for commands you forget
- **Jujutsu** - Git-compatible VCS with better UX
- **Presenterm** - Terminal-based presentations
- **Asciinema** - Record terminal sessions
- **mdbook** - Generate documentation sites

All are installed via Nix, so they're reproducible across machines and don't pollute your global system.
Empty file added book/src/tools/jj.md
Empty file.
Loading