Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

flk is a modern CLI tool for managing Nix flake development environments with the simplicity of tools like Devbox. It provides an intuitive interface for working with Nix flakes without manually editing configuration files.

Why flk?

  • 🎯 Smart Initialization: Auto-detects your project type
  • πŸ“¦ Easy Package Management: Add/remove packages with simple commands
  • ⚑ Custom Commands: Define reusable shell commands
  • 🌍 Environment Management: Manage environment variables easily
  • πŸ”’ Lock File Management: Version control for your dependencies

Quick Example

# Initialize a Rust project
flk init

# Add packages
flk add ripgrep fd-find

# Define a custom command
flk cmd add build "cargo build --release"

# Enter the development environment
nix develop

# Use your custom command
build

Upgrading to v0.5.X (switch/refresh changes)

WARNING (pre v0.5.0 users): If you are using flk < v0.5.0 and you run flk update / nix flake update, your devshell switch / refresh behavior may break because the nix-profile-lib input may update to a newer version with different activation semantics.

If you intend to stay on flk < v0.5.0, use one of these options:

  1. Do not update flake inputs. Avoid running flk update or nix flake update. If you already did, restore a previous lockfile backup with:

    flk lock restore <BACKUP>
    
  2. Pin nix-profile-lib to v0.1.0. In your flake.nix:

    inputs = {
      nix-profile-lib.url = "github:AEduardo-dev/nix-profile-lib?ref=v0.1.0";
    };
    

    Then update the lock entry:

    nix flake lock --update-input nix-profile-lib
    

    (or nix flake update --update-input nix-profile-lib)

Once you upgrade to flk v0.5.0+, this restriction is lifted.

Documentation Structure

  • User Guide: Learn how to use flk effectively
  • Commands: Detailed reference for all commands
  • Advanced Topics: Deep dives into specific features
  • API Documentation: Internal API reference for contributors

Getting Help

Installation

Prerequisites

  • Nix with flakes enabled
    • We recommend the Lix package manager for easy Nix installation: Lix since it comes with flakes enabled by default.
    • Or using the Determinate System installer: Determinate, as it provides a user-friendly way to install (and uninstall) Nix.
  • Rust 1.83+ (if building from source)

Hooks

If you would like to use hot reloading and switching features, you will need to add the following shell hook to your shell configuration file (~/.bashrc, ~/.zshrc, etc.):

Example for bash:

# flk shell hook
if command -v flk &> /dev/null; then
  eval "$(flk hook bash)"
fi

Support for other shells (zsh and fish) is also available via flk hook <shell>.

From Source

git clone https://github.com/AEduardo-dev/flk.git
cd flk
cargo build --release
sudo cp target/release/flk /usr/local/bin/

From Cargo (crates.io)

cargo install flk

From Release Binaries

  1. Go to https://github.com/AEduardo-dev/flk/releases
  2. Download the archive for your OS/arch (Linux x86_64, macOS Intel, macOS ARM).
  3. Unpack and place flk in your PATH.

Nix (with Cachix binaries)

This flake is prebuilt and published to Cachix.

  1. Install Cachix (once):
nix profile install nixpkgs#cachix
  1. Trust the cache:
cachix use flk-cache

or add the following substituters and trusted-public-keys to your nix.conf content:

substituters = https://flk-cache.cachix.org  ...
trusted-public-keys = flk-cache.cachix.org-1:6xobbpP9iIK5sIH/75DQrsJYKN/61nTOChcH9MJnBR0=  ...
  1. Use the flake:
  • Run (no install): nix run github:AEduardo-dev/flk#flk
  • Install to your profile: nix profile install github:AEduardo-dev/flk#flk

Nix – Using as a flake input

You can consume flk from another flake either directly or via the overlay.

Direct (no overlay):

{
  description = "My NixOS config with flk";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flk.url = "github:AEduardo-dev/flk";
  };

  outputs = { self, nixpkgs, flk, ... }:
    let
      system = "x86_64-linux"; # set per host
      pkgs = import nixpkgs { inherit system; };
    in {
      nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          {
            environment.systemPackages = [
              flk.packages.${system}.flk
            ];
          }
        ];
      };
    };
}

With overlay (exposes pkgs.flk):

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  inputs.flk.url = "github:AEduardo-dev/flk";

  outputs = { self, nixpkgs, flk, ... }:
    let
      system = "x86_64-linux"; # set per host

      pkgs = import nixpkgs {
        inherit system;
        overlays = [ flk.overlay ];
      };
    in {
      nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          { environment.systemPackages = [ pkgs.flk ]; }
        ];
      };
    };
}

Home Manager example (per-user install via flake):

{
  inputs.flk.url = "github:AEduardo-dev/flk";

  outputs = { self, flk, ... }: {
    homeConfigurations.myhost = {
      # ...
      home.packages = [ flk.packages.${system}.flk ];
    };
  };
}

Architectures covered by the cache

  • x86_64-linux
  • x86_64-darwin
  • aarch64-darwin
  • aarch64-linux (built via qemu on CI; may be slower/occasional misses)

Other architectures will fall back to building from source.

Next Steps

πŸš€ Getting Started

1. Initialize Your Project

# Auto-detect project type and create flake.nix
flk init

# Or specify a template
flk init --template rust
flk init --template python
flk init --template node
flk init --template go

Supported auto-detection:

  • Cargo.toml β†’ Rust template
  • package.json β†’ Node.js template
  • pyproject.toml or requirements.txt β†’ Python template
  • go.mod β†’ Go template

2. Add Packages

# Search for packages
flk search ripgrep

# Get detailed package info and versions
flk deep-search ripgrep

# Add packages to your environment
flk add ripgrep
flk add git
flk add neovim

# Or add pinned versions
flk add ripgrep --version '15.1.0'
flk add git --version '2.42.0'

3. Add Custom Commands

# Add inline commands
flk command add test "cargo test --all"
flk command add dev "npm run dev"

4. Manage Environment Variables

# Add environment variables
flk env add DATABASE_URL "postgresql://localhost/mydb"
flk env add API_KEY "your-api-key"

# List all environment variables
flk env list

# Remove an environment variable
flk env remove API_KEY

5. Enter Your Development Environment

flk activate

Your custom commands and environment variables will be automatically available!

6. Generate completions

# Generates the completion file and prints it
flk completions

# Install the generated completions to the detected shell
flk completions --install

Follow the instructions after the command to make the completions available for you.

7. Attach to your direnv (optional)

If you use direnv, you can set it up to automatically load your flk environment when you enter the project directory.

# Generates a .envrc file for direnv with use flake command
flk direnv init

#or

# Add the direnv hook to an existing project
flk direnv attach

if you ever want to detach the direnv hook, you can run:

flk direnv detach

8. Switch / Refresh your environment

Add the following to your shell profile (~/.bashrc, ~/.zshrc, etc.) to enable switching and refreshing of your flk environment when you navigate between project directories: e.g. Bash

eval "$(flk hook bash)"

Currently supported shells are: bash, zsh and fish.

Next Steps

Core Concepts Commands

Core Concepts

flk is built around a few core concepts that help you manage your development environments effectively. Understanding these concepts will help you make the most out of flk.

Projects

A project in flk is a directory that contains a flake.nix file. This file is the entry point to the environment for that project, including dependencies, custom commands, and environment variables.

When you navigate to a project directory and activate the flk environment, flk reads the profile.nix file and sets up the environment accordingly, using the files located in the .flk/profiles/ directory.

Profiles

Profiles are a way to manage different sets of dependencies and configurations for your projects. Each profile corresponds to a specific profile.nix configuration and is stored in the .flk/profiles/ directory. You can switch between profiles using the switch command (given you set up the hook for your shell accordingly), allowing you to easily change your development environment based on the project you’re working on.

Custom Commands

Custom commands are user-defined scripts that can be added to your flk environment. These commands are defined in the profile.nix file and can be executed directly from the command line when the flk environment is activated. This allows you to create project-specific tools and utilities that are easily accessible.

Environment Variables

Environment variables are key-value pairs that can be set within your flk environment. They are defined in the profile.nix file and are automatically loaded when you activate the flk environment for a project. This allows you to manage project-specific configurations, such as API keys or database URLs, without affecting your global environment.

Warning CAUTION: Be careful not to store sensitive information in plain text within your profile.nix file, especially if the project is shared or version-controlled.

Lock Files

Lock files are used to ensure that the dependencies for your flk projects remain consistent across different environments and over time. The lock file records the exact versions of dependencies used in your project, allowing you to reproduce the same environment later or on different machines. You can manage the lock file using the flk lock together with flk update commands.

Overlays

Overlays are a powerful feature in flk that allow you to customize and extend the Nix package set used in your projects. By defining overlays in your environment, your profiles can modify existing packages or add new ones, tailoring the environment to your specific needs. This is particularly useful for projects that require specific versions of packages or custom builds, and is tightly integrated with the flk’s lock file management to ensure consistency.

Shell Integration

flk integrates with your shell to provide a seamless experience when working with different projects. By setting up shell hooks, flk can expose a set of convenient commands that allow you to switch between profiles, and hot reload them. This integration enhances productivity by making it easy to work within the context of your flk-managed projects without the need to exit and re-enter your shell environment on every change.

Direnv Integration

flk can also integrate with direnv, a popular tool for managing environment variables based on the current directory. By using the flk direnv init command, you can generate a .envrc file that automatically loads your flk environment whenever you enter the project directory. This integration simplifies the workflow by ensuring that your development environment is always correctly set up without manual intervention.

Flk provides a set of commands flk direnv to help you manage this integration, making it easy to set up and maintain your development environments with direnv.

Container Exporting

flk supports exporting your development environment to container formats like Docker and Podman. This feature allows you to create portable and reproducible environments that can be easily shared and deployed across different systems. By using the flk export command, you can generate container images that encapsulate your project’s dependencies, custom commands, and environment variables. This is particularly useful if flk is not natively supported on your target system, or if you want to ensure consistency across development, testing, and production environments.

Examples

This page provides complete, practical examples for common development scenarios.

Python Data Science Environment

Set up a complete data science environment with Jupyter, scientific packages, and helper commands.

# Initialize Python project
flk init --template python

# Add Python and data science packages
flk add python312
flk add python312Packages.numpy
flk add python312Packages.pandas
flk add python312Packages.matplotlib
flk add python312Packages.scikit-learn
flk add jupyter

# Add convenience commands
flk cmd add notebook "jupyter notebook --port=8888"
flk cmd add lab "jupyter lab --port=8888"
flk cmd add ipython "python -m IPython"

# Configure environment
flk env add JUPYTER_CONFIG_DIR "./.jupyter"
flk env add PYTHONDONTWRITEBYTECODE "1"

# Enter environment and start working
flk activate
notebook

Rust Web Backend

Full-stack Rust development with database, caching, and development tools.

# Initialize Rust project
flk init --template rust

# Add development dependencies
flk add postgresql
flk add redis
flk add sqlx-cli
flk add cargo-watch

# Add development commands
flk cmd add dev "cargo watch -x run"
flk cmd add test "cargo test --all-features"
flk cmd add migrate "sqlx migrate run"
flk cmd add db "psql $DATABASE_URL"

# Configure database connection
flk env add DATABASE_URL "postgresql://localhost/myapp"
flk env add REDIS_URL "redis://localhost:6379"
flk env add RUST_LOG "debug"

# Activate and start development
flk activate
dev

Node.js Full-Stack Application

Modern JavaScript/TypeScript development with database and tooling.

# Initialize Node project
flk init --template node

# Add runtime and tools
flk add nodejs_20
flk add postgresql
flk add docker-compose
flk add nodePackages.typescript
flk add nodePackages.eslint

# Add development commands
flk cmd add dev "npm run dev"
flk cmd add build "npm run build"
flk cmd add db:start "docker-compose up -d postgres"
flk cmd add db:stop "docker-compose down"
flk cmd add lint "npm run lint"
flk cmd add typecheck "tsc --noEmit"

# Set environment variables
flk env add NODE_ENV "development"
flk env add DATABASE_URL "postgresql://localhost/myapp"
flk env add PORT "3000"

# Start development
flk activate
db:start
dev

Go Microservice

Go development with common tools and testing setup.

# Initialize Go project
flk init --template go

# Add Go and tools
flk add go
flk add gopls
flk add golangci-lint
flk add mockgen
flk add protobuf

# Add commands
flk cmd add run "go run ./cmd/server"
flk cmd add test "go test ./..."
flk cmd add lint "golangci-lint run"
flk cmd add proto "protoc --go_out=. --go-grpc_out=. ./proto/*.proto"
flk cmd add build "go build -o bin/server ./cmd/server"

# Configure
flk env add GOPROXY "https://proxy.golang.org,direct"
flk env add CGO_ENABLED "0"

# Activate
flk activate
run

Multi-Language Monorepo

For projects with multiple languages, you can create separate profiles.

# Initialize with generic template
flk init --template generic

# The default profile is in .flk/profiles/default.nix
# You can create additional profiles by copying and modifying:
# .flk/profiles/frontend.nix
# .flk/profiles/backend.nix

# Add shared tools to default profile
flk add git
flk add docker-compose
flk add make

# Add commands that work across the project
flk cmd add up "docker-compose up -d"
flk cmd add down "docker-compose down"
flk cmd add logs "docker-compose logs -f"

Pinning Package Versions

When you need reproducible builds with specific versions:

# Pin specific package versions
flk add ripgrep --version 14.1.0
flk add nodejs --version 20.10.0
flk add python3 --version 3.11.6

# View what's pinned
flk list packages

# The version info is stored in .flk/pins.nix

Using with Direnv

Automatically activate environments when entering directories:

# Set up direnv integration
flk direnv init

# Allow the .envrc file
direnv allow

# Now the environment loads automatically when you cd into the project
cd ~/projects/myapp  # Environment activates
cd ~                 # Environment deactivates

Container Export for CI/CD

Export your development environment for use in CI or on machines without Nix:

# Export as Docker image
flk export --format docker

# Export as Podman image
flk export --format podman

# Export configuration as JSON (useful for debugging or other tools)
flk export --format json

Project Templates

flk uses templates to scaffold development environments tailored to your project’s language and toolchain.

Using Templates

flk init --template rust
flk init --template python
flk init --template node
flk init --template go
flk init --template generic

Auto-Detection

If you omit --template, flk auto-detects the project type by looking for:

FileDetected Template
Cargo.tomlrust
package.jsonnode
pyproject.toml or requirements.txtpython
go.modgo
(none found)generic

Available Templates

base

Minimal template with no language-specific tools. Used as the default when creating profiles via flk profile add.

rust

Includes Rust toolchain essentials:

  • Rust compiler and Cargo
  • Common development tools (rust-analyzer, clippy, rustfmt)
  • Build dependencies (pkg-config, openssl)

python

Includes Python development essentials:

  • Python interpreter
  • pip and virtualenv support
  • Common development tools

node

Includes Node.js development essentials:

  • Node.js runtime
  • npm package manager
  • Common development tools

go

Includes Go development essentials:

  • Go compiler
  • Go tools (gopls, etc.)

generic

A minimal starting point with basic utilities. Use this when your project doesn’t fit a specific language category or when you want to build a custom environment from scratch.

Template Files

Templates are stored in the templates/ directory of the flk source and are embedded at compile time:

  • templates/flake.nix β€” Root flake template
  • templates/default.nix β€” Profile loader/importer
  • templates/pins.nix β€” Version pinning structure
  • templates/overlays.nix β€” Package overlays
  • templates/profiles/*.nix β€” Language-specific profile templates

Creating Additional Profiles

After initialization, you can create additional profiles from any template:

flk profile add backend --template rust
flk profile add frontend --template node
flk profile add scripts --template python

See Also

Custom Commands

Custom commands let you define reusable scripts in your flk environment. They become available as shell functions when the development environment is activated.

Basic Usage

flk cmd add dev "npm run dev"
flk cmd add test "cargo test --all"
flk cmd add lint "cargo clippy -- -D warnings"
flk cmd list
flk cmd remove dev

Loading from Files

For complex or multiline commands, use the --file flag:

flk cmd add deploy --file scripts/deploy.sh

This reads the command body from the specified file instead of inline text.

Profile Targeting

Commands are stored per-profile. Use --profile to target a specific one:

flk cmd add build "cargo build --release" --profile backend
flk cmd list --profile frontend

How It Works

Commands are stored in the commands block of your profile file (.flk/profiles/<profile>.nix):

commands = [
  { name = "dev"; script = ''npm run dev''; }
  { name = "test"; script = ''cargo test --all''; }
];

Each command becomes a shell function (via writeShellScriptBin) when you activate the environment.

Naming Rules

Command names must follow these rules:

  • Letters, numbers, hyphens, and underscores only
  • Cannot start with a hyphen
  • Examples: dev, run-tests, build_release

Examples

# Web development commands
flk cmd add dev "npm run dev"
flk cmd add build "npm run build && npm run typecheck"
flk cmd add db:migrate "npx prisma migrate dev"

# Rust project commands
flk cmd add watch "cargo watch -x 'run -- --port 8080'"
flk cmd add bench "cargo bench --all-features"

# Complex command from a file
echo '#!/bin/bash
echo "Running full CI pipeline..."
cargo fmt --check
cargo clippy -- -D warnings
cargo test --all' > scripts/ci.sh
flk cmd add ci --file scripts/ci.sh

See Also

Environment Variables

Manage per-project environment variables without touching your global shell configuration.

Basic Usage

flk env add DATABASE_URL "postgresql://localhost:5432/mydb"
flk env add NODE_ENV "development"
flk env remove DATABASE_URL
flk env list

Profile Targeting

Environment variables are stored per-profile. Use --profile to target a specific one:

flk env add API_URL "http://localhost:3000" --profile backend
flk env list --profile frontend

How It Works

Variables are stored in the envVars block of your profile file (.flk/profiles/<profile>.nix):

envVars = {
  DATABASE_URL = "postgresql://localhost:5432/mydb";
  NODE_ENV = "development";
};

They are automatically exported when you activate the environment via flk activate, nix develop, or direnv.

Naming Rules

Variable names must follow these rules:

  • Start with a letter or underscore
  • Contain only letters, numbers, and underscores
  • Examples: DATABASE_URL, MY_VAR, _PRIVATE_KEY
  • Invalid: 123VAR, my-var, my var

Security Considerations

Warning: Do not store secrets (API keys, passwords, tokens) directly in profile files, especially if your project is version-controlled.

For sensitive values, consider:

  • Using direnv with a .envrc.local file (add to .gitignore)
  • Referencing secrets from a secrets manager at runtime
  • Using environment-specific tooling outside of flk

See Also

Lock File Management

flk protects your flake.lock file with automatic backups, preview-before-update, and easy rollback.

Commands

flk lock show              # inspect current lock file
flk lock history           # list available backups
flk lock restore latest    # restore most recent backup
flk update                 # update inputs (creates backup first)
flk update --show          # preview updates without applying

How It Works

Automatic Backups

Every time you run flk update, a backup of the current flake.lock is created before any changes are made. Backups are stored in .flk/backups/ with timestamped filenames:

.flk/backups/
β”œβ”€β”€ flake.lock.2025-01-27_14-30-00
β”œβ”€β”€ flake.lock.2025-02-15_09-45-22
└── flake.lock.2025-03-01_16-00-00

Preview Updates

Use flk update --show to see what would change without modifying your lock file:

flk update --show

This temporarily updates the lock file, shows the diff, then restores the original β€” a safe way to check for upstream changes.

Inspecting the Lock File

flk lock show

Displays structured information about each input in your flake.lock, including:

  • Input name and type (e.g., github, indirect)
  • Source URL
  • Current revision/commit
  • Last modified date

Viewing Backup History

flk lock history

Lists all available backups with their timestamps and sizes, so you can identify which snapshot to restore.

Restoring a Backup

flk lock restore latest                    # most recent backup
flk lock restore 2025-01-27_14-30-00       # specific timestamp

Replaces the current flake.lock with the selected backup.

Interaction with Version Pinning

When you pin a package version with flk add --version, the pinning data is stored in .flk/pins.nix (not in flake.lock). Lock file backups and restores do not affect version pins β€” they only manage the Nix input lock state.

Best Practices

  • Run flk update --show before flk update to review changes
  • Use flk lock restore latest immediately if an update causes issues
  • Backups accumulate over time; periodically clean old ones from .flk/backups/ if needed

See Also

Commands Overview

flk ships a small set of focused subcommands. They fall into a few groups:

  • Project setup: flk init, flk activate, flk hook <shell>, direnv helpers, flk profile
  • Packages: flk search, flk deep-search, flk add, flk remove, flk list, flk show
  • Customization: flk cmd, flk env, flk export
  • State management: flk lock, flk update
  • Developer experience: flk completions

Each command description below is intentionally shortβ€”see the examples on each page and the README for longer walkthroughs.

flk activate

Enter the Nix development shell for your project.

flk activate
flk activate --profile backend

Options

  • -p, --profile <PROFILE>: Activate a specific profile instead of the default

Behavior

  • Runs nix develop .#<profile> --impure to enter the dev shell
  • Reuses a cached develop profile from .flk/.nix-profile-<profile> when your flake config is unchanged
  • Refreshes that cached profile when flake.nix, flake.lock, or the relevant .flk profile files change
  • Uses standard profile resolution when --profile is not specified
  • Custom commands and environment variables from the profile are available inside the shell

Notes

  • For automatic environment switching when navigating between projects, add the shell hook:
    eval "$(flk hook bash)"   # or zsh/fish
    
  • For automatic activation when entering a directory, use direnv integration

See Also

  • flk hook β€” for refresh and switch commands
  • flk direnv β€” for automatic directory-based activation

flk add

Add a package to your flake.nix.

flk add ripgrep
flk add git
flk add nodejs
flk add ripgrep --version '15.1.0'   # pinned version
flk add cargo-watch --profile backend  # specific profile

Options

  • -v, --version <VERSION>: pin to a specific version
  • -p, --profile <PROFILE>: target a specific profile instead of the default

Behavior

  • Validates the package exists (nix-versions).
  • Writes to .flk/profiles/<profile>.nix; updates .flk/pins.nix when pinning.
  • Fails if the package is already present.

flk cmd

Manage custom shell commands for your flk environment.

flk cmd add dev "npm run dev"
flk cmd add test "cargo test --all"
flk cmd list
flk cmd remove dev

Subcommands

  • add <NAME> <COMMAND> [--file <PATH>]: add a command (inline or from file)
  • remove <NAME>: delete a command
  • list: list all custom commands

Options

  • -p, --profile <PROFILE>: target a specific profile instead of the default

Notes

  • Command names: letters, numbers, hyphens, underscores; cannot start with hyphen.

flk completions

Generate shell completions.

flk completions            # print to stdout
flk completions --install  # auto-install for detected shell
flk completions --shell zsh

Options

  • --install: install to the detected shell location
  • --shell <SHELL>: override shell detection (bash, zsh, fish, etc.)

flk deep-search

Get detailed version and attribute information about a specific package from nixpkgs.

flk deep-search ripgrep
flk deep-search python3

Behavior

  • Queries nixpkgs using nix-versions under the hood
  • Displays available versions, attribute paths, and package metadata
  • More detailed than flk search, which only lists matching package names

Example Output

Package: ripgrep
  Version: 14.1.1
  Attribute: ripgrep
  Description: A utility that combines the usability of The Silver Searcher with the raw speed of grep

When to Use

  • Use flk search <term> to find packages by name
  • Use flk deep-search <package> to inspect a specific package in detail, especially to find available versions for pinning

See Also

flk env

Manage environment variables for your dev shell.

flk env add DATABASE_URL "postgresql://localhost:5432/mydb"
flk env remove DATABASE_URL
flk env list

Subcommands

  • add <NAME> <VALUE>: add/update a variable
  • remove <NAME>: delete a variable
  • list: show all configured variables

Options

  • -p, --profile <PROFILE>: target a specific profile instead of the default

Notes

  • Names must start with a letter/underscore and contain only letters, numbers, underscores.

flk export

Export the current flake configuration to Docker, Podman, or JSON.

flk export --format docker
flk export --format podman
flk export --format json
flk export --format docker --profile backend

Options

  • -f, --format <FORMAT>: Export format β€” docker, podman, or json (required)
  • -p, --profile <PROFILE>: Target a specific profile instead of the default

Formats

Docker

Builds a Nix-based Docker image from the flake and loads it into the local Docker daemon.

  • Requires Docker to be installed and running
  • The image is built via nix build .#docker-<profile> and loaded with docker load
  • Output image is stored at .flk/result before loading

Podman

Same as Docker but uses Podman instead.

  • Requires Podman to be installed and running
  • Built via nix build .#podman-<profile> and loaded with podman load

JSON

Serializes the parsed flake configuration to a flake.json file in the project root.

  • Includes all profiles, packages, environment variables, and inputs
  • Useful for debugging, CI pipelines, or integrating with other tools
  • Does not require Docker or Podman

Notes

  • Docker and Podman exports use --impure for Nix builds
  • Uses standard profile resolution when --profile is not specified

See Also

flk hook

Generate shell hooks that enable the refresh and switch commands for hot-reloading your development environment.

flk hook bash
flk hook zsh
flk hook fish

Usage

Add the hook output to your shell profile to enable refresh and switch:

# Bash (~/.bashrc)
eval "$(flk hook bash)"

# Zsh (~/.zshrc)
eval "$(flk hook zsh)"

# Fish (~/.config/fish/config.fish)
flk hook fish | source

Supported Shells

  • bash
  • zsh
  • fish

Commands Provided by the Hook

Once sourced, two shell functions become available:

refresh

Reload the current development environment. Picks up changes you’ve made (added packages, env vars, commands) without leaving the shell.

# After adding a package
flk add ripgrep
refresh
  • If direnv is present and .envrc exists, runs direnv reload
  • Otherwise, reuses a cached nix develop profile when it is still fresh
  • Rebuilds that cached profile when the flake inputs or relevant .flk files change
  • Uses FLK_FLAKE_REF (fallback: FLK_PROFILE) to determine the active profile

switch <profile>

Switch to a different profile and reload the environment.

switch backend
switch frontend
  • Validates the profile name before switching
  • Updates FLK_FLAKE_REF and FLK_PROFILE, then reloads via direnv or nix develop
  • Reuses the saved profile cache until the environment definition changes

Notes

  • The hook integrates with direnv automatically β€” if .envrc is present, it uses direnv reload instead of exec nix develop
  • Profile names must be alphanumeric (with - or _)
  • See also: flk activate, flk direnv

flk init

Initialize a new flake.nix for your project.

flk init                    # Auto-detect project type
flk init --template rust    # Use Rust template
flk init --force            # Overwrite existing flake.nix

Options

  • -t, --template <TYPE>: rust, python, node, go, generic (auto-detect if omitted)
  • -f, --force: overwrite an existing flake.nix

What it does

  • Creates flake.nix, .flk/ helper files, and a default profile under .flk/profiles/
  • Auto-detects project type from common files (Cargo.toml, package.json, pyproject/requirements, go.mod)
  • Prints next steps, including adding flk hook <shell> to your shell config

flk lock

Manage flake.lock backups and inspection.

flk lock show              # show lock info
flk lock history           # list backups
flk lock restore latest    # restore most recent backup
flk lock restore 2025-01-27_14-30-00

Subcommands

  • show: pretty-prints lock details
  • history: lists available backups
  • restore <BACKUP>: restores a backup (timestamp or latest)

flk list

List all packages in the current profile.

flk list
flk list --profile backend

Options

  • -p, --profile <PROFILE>: Target a specific profile instead of the default

Behavior

  • Reads .flk/profiles/<profile>.nix and displays all packages in the packages = [ ... ]; section
  • Uses standard profile resolution when --profile is not specified
  • Outputs one package per line with a bullet marker
  • Shows an error message if no packages are found

Example Output

β€’ ripgrep
β€’ fd
β€’ git
β€’ nodejs_20

flk remove

Remove a package from your flake.nix.

flk remove ripgrep
flk remove ripgrep --profile backend

Options

  • -p, --profile <PROFILE>: target a specific profile instead of the default

Behavior

  • Removes from .flk/profiles/<profile>.nix.
  • Cleans up pinned entries from .flk/pins.nix when needed.
  • Errors if the package is not present.

flk search

Search nixpkgs for packages.

flk search ripgrep
flk search python --limit 20

Options

  • -l, --limit <NUMBER>: number of results (default 10)

Notes

  • Uses nix-versions under the hood.
  • For detailed info, use flk deep-search <PACKAGE>.

flk show

Pretty-print the current flake configuration for inspection.

flk show

Behavior

  • Parses flake.nix and all profiles in .flk/profiles/
  • Displays a structured summary including:
    • Flake inputs (name, URL, type)
    • Each profile with its packages, environment variables, and custom commands
  • Useful for verifying your configuration at a glance without reading raw Nix files

Example Output

Flake Inputs:
  nixpkgs: github:NixOS/nixpkgs/nixos-unstable (indirect)
  nix-profile-lib: github:AEduardo-dev/nix-profile-lib (github)

Profile: rust
  Packages:
    β€’ ripgrep
    β€’ cargo-watch
  Environment Variables:
    RUST_LOG = "debug"
  Commands:
    dev: cargo watch -x run
    test: cargo test --all

Notes

  • Shows all profiles, not just the default
  • Read-only β€” does not modify any files

flk switch / refresh

Shell commands for hot-reloading and profile switching within an active development environment. These are provided by the flk hook and are not standalone flk subcommands.

Setup

Add the shell hook to your profile:

# Bash
eval "$(flk hook bash)"

# Zsh
eval "$(flk hook zsh)"

# Fish
flk hook fish | source

refresh

Reload the current environment to pick up configuration changes.

# Make changes
flk add ripgrep
flk env add MY_VAR "hello"

# Apply without leaving the shell
refresh

Behavior

  • With direnv: runs direnv reload
  • Without direnv: reuses a saved nix develop profile when it is current
  • Without direnv: refreshes that saved profile when the environment definition changes
  • Reads the active profile from FLK_FLAKE_REF (fallback: FLK_PROFILE)

switch <profile>

Switch to a different profile and reload the environment.

switch backend
switch frontend

Behavior

  • Validates the profile name (alphanumeric, -, _ only)
  • Sets FLK_FLAKE_REF and FLK_PROFILE to the new profile reference
  • Reloads via direnv or nix develop as appropriate, reusing the saved profile cache when possible

Direnv Integration

When direnv is available and .envrc exists, both refresh and switch use direnv reload for a seamless experience. Without direnv, they use exec nix develop, which replaces the current shell process.

Notes

  • Supported shells: bash, zsh, fish
  • Requires the flk shell hook to be sourced in your shell profile
  • See also: flk hook, flk activate

flk update

Update all flake inputs (creates a lockfile backup first).

flk update           # apply updates
flk update --show    # preview without applying

Options

  • --show: check for updates without modifying flake.lock

Behavior

  • Backs up flake.lock to .flk/backups before applying.
  • Uses nix flake update; preview restores the original lockfile after diffing.

flk direnv

Integrate flk with direnv.

flk direnv init    # create .envrc with use flake
flk direnv attach  # add hook to existing .envrc
flk direnv detach  # remove hook

Subcommands

  • init: generate .envrc
  • attach: add hook to existing .envrc
  • detach: remove hook

flk profile

Manage profiles for your flk project. Profiles let you maintain separate sets of packages, commands, and environment variables within the same project.

Subcommands

flk profile add

Create a new profile from a template.

flk profile add backend
flk profile add frontend --template node
flk profile add ci --template base --force

Options

  • <NAME>: Profile name (alphanumeric, hyphens, underscores only)
  • -t, --template <TYPE>: Template to use (base, rust, python, node, go, generic). Defaults to base
  • -f, --force: Overwrite if profile already exists

Behavior

  • Creates .flk/profiles/<NAME>.nix from the selected template
  • Profile names are validated β€” no path separators or spaces allowed
  • Fails if the profile already exists unless --force is used

flk profile remove

Remove an existing profile.

flk profile remove frontend

Behavior

  • Deletes .flk/profiles/<NAME>.nix
  • Cannot remove the profile that is currently set as default β€” change the default first with flk profile set-default

flk profile list

List all available profiles.

flk profile list

Behavior

  • Lists all .nix files in .flk/profiles/ (excluding default.nix)
  • Profiles are sorted alphabetically

flk profile set-default

Set which profile is used when no --profile flag is provided.

flk profile set-default backend

Behavior

  • Updates the defaultShell attribute in .flk/default.nix
  • The specified profile must already exist
  • Affects all commands that use profile resolution (add, remove, list, activate, export, cmd, env)

Profile Resolution

When you run a command without --profile, flk resolves the profile in this order:

  1. Explicit --profile / -p argument
  2. FLK_FLAKE_REF environment variable
  3. defaultShell in .flk/default.nix
  4. First available profile in .flk/profiles/

Examples

# Set up a multi-profile project
flk init --template generic

# Create specialized profiles
flk profile add backend --template rust
flk profile add frontend --template node

# Add packages to specific profiles
flk add cargo-watch --profile backend
flk add nodejs_20 --profile frontend

# Switch the default
flk profile set-default backend

# Now commands target "backend" by default
flk add ripgrep          # goes to backend profile
flk add eslint --profile frontend  # explicit override

See Also

Architecture

This page describes the internal architecture of flk for contributors and curious users.

Overview

flk is a Rust CLI application that generates and modifies Nix flake configurations. It acts as a user-friendly layer on top of Nix, handling the complexity of flake syntax and structure.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     flk CLI                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  Commands   β”‚  β”‚   Parsers   β”‚  β”‚  Generator  β”‚     β”‚
β”‚  β”‚ (clap CLI)  β”‚  β”‚ (nom-based) β”‚  β”‚ (templates) β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Nix Flake Files                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  flake.nix  β”‚  β”‚ .flk/       β”‚  β”‚ flake.lock  β”‚     β”‚
β”‚  β”‚   (root)    β”‚  β”‚ profiles/   β”‚  β”‚  (inputs)   β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Crate Structure

  • Binary crate (src/main.rs): CLI entrypoint using clap. Parses arguments and dispatches to command handlers in src/commands/.

  • Library crate (src/lib.rs): Core functionality exposed as a library:

    • flk::flake - Flake generation, parsing, and interfaces
    • flk::utils - Backup management, visual output, helpers
  • Nix integration (src/nix/): Wrappers for invoking nix commands (search, evaluate, develop) and processing output.

Parser Design

Parsers in src/flake/parsers/ use the nom library to read and modify specific sections of Nix files:

  • Surgical editing: Instead of parsing entire Nix files, parsers target specific sections (packages, env vars, commands) and track byte positions for precise modifications.
  • Round-trip safety: Parse β†’ modify struct β†’ render back to Nix syntax, preserving comments and formatting outside the edited section.

Each parser returns a section struct containing:

  • Parsed entries (packages, variables, etc.)
  • Byte positions (section_start, section_end, list_end)
  • Indentation information for consistent formatting

Template System

Templates in templates/ are embedded at compile time via include_str!:

  • templates/flake.nix - Root flake template
  • templates/default.nix - Default profile loader
  • templates/pins.nix - Version pinning structure
  • templates/profiles/*.nix - Language-specific profiles (rust, python, node, go, generic)

The generator (src/flake/generator.rs) selects and instantiates these templates based on project type.

Data Layout

A flk-managed project has this structure:

project/
β”œβ”€β”€ flake.nix           # Root flake (generated by flk init)
β”œβ”€β”€ flake.lock          # Nix lock file (managed by Nix)
└── .flk/
    β”œβ”€β”€ default.nix     # Default profile selector
    β”œβ”€β”€ pins.nix        # Version pinning data
    β”œβ”€β”€ overlays.nix    # Package overlays
    β”œβ”€β”€ profiles/
    β”‚   β”œβ”€β”€ default.nix # Default profile (symlink or import)
    β”‚   β”œβ”€β”€ rust.nix    # Language-specific profile
    β”‚   └── ...
    └── backups/        # Lockfile backups from flk update

Command Flow

  1. CLI parsing: clap in src/main.rs parses arguments
  2. Command dispatch: Each subcommand calls a run_* function in src/commands/
  3. File operations: Commands use parsers to read/modify .flk/ files
  4. Nix operations: Search, version lookup, and activation run through nix wrappers
  5. User feedback: Spinners and formatted output via src/utils/visual.rs

Key Interfaces

  • FlakeConfig: Complete flake configuration with profiles, packages, env vars
  • Profile: Single profile with packages, commands, environment variables
  • Package: Package entry with name and optional version pin
  • SourcesSection / OverlaysSection: Version pinning data structures

API Documentation

The flk library exposes Rust APIs for programmatic access to flake generation and parsing.

Generating Documentation

Build the API documentation locally:

cargo doc --no-deps --open

Or with all features and dependencies:

cargo doc --all-features --open

Module Overview

flk::flake

Core flake functionality:

  • flk::flake::generator - Template loading and flake generation

    • generate_flake(project_type) - Generate profile content for a project type
    • generate_helper_module() - Generate the .flk/default.nix loader
    • generate_pins() - Generate empty pins file
  • flk::flake::parsers - Nix file parsing and modification

    • packages - Parse/modify packages = [ ... ]; sections
    • env - Parse/modify envVars = { ... }; sections
    • commands - Parse/modify shell hook commands
    • overlays - Parse/modify pins.nix for version pinning
    • flake - Parse top-level flake structure
    • utils - Profile resolution and parsing helpers
  • flk::flake::interfaces - Data structures

    • FlakeConfig - Complete flake configuration
    • Profile - Single profile with packages, commands, env vars
    • Package - Package entry with optional version
    • EnvVar - Environment variable key-value pair
  • flk::flake::nix_render - Safe Nix syntax rendering

    • nix_string(s) - Escape string for Nix double-quoted strings
    • nix_attr_key(s) - Format attribute key (quote if needed)

flk::utils

Utility functions:

  • flk::utils::backup - Lockfile backup management
  • flk::utils::visual - Spinner and progress display

Example Usage

#![allow(unused)]
fn main() {
use flk::flake::generator::generate_flake;
use flk::flake::parsers::packages::parse_packages_section;

// Generate a Rust profile template
let profile_content = generate_flake("rust")?;

// Parse packages from an existing profile
let content = std::fs::read_to_string(".flk/profiles/rust.nix")?;
let section = parse_packages_section(&content)?;

// Add a package (returns new content directly)
let new_content = section.add_package(&content, "ripgrep", None);
std::fs::write(".flk/profiles/rust.nix", new_content)?;
}

Contributing to the API

When contributing:

  • Document all public items with /// doc comments
  • Include # Arguments, # Returns, and # Errors sections where applicable
  • Add examples in doc comments for non-obvious behavior
  • Run cargo doc --no-deps before submitting to check for warnings
  • Keep internal/unstable functions prefixed with underscore (_parse_*)

Troubleshooting

This page covers common issues and their solutions.

Nix Not Found

Symptom: command not found: nix or flk commands fail with Nix errors.

Solution:

  1. Ensure Nix is installed: curl -L https://nixos.org/nix/install | sh
  2. Verify installation: nix --version
  3. Enable flakes in ~/.config/nix/nix.conf:
    experimental-features = nix-command flakes
    
  4. Restart your shell or run source ~/.bashrc

Search/Version Lookup Errors

Symptom: flk search or flk add --version fails with network or evaluation errors.

Solution:

  • These commands use nix run github:vic/nix-versions which requires network access
  • Check your internet connection
  • Try running directly: nix run github:vic/nix-versions -- -p ripgrep
  • If behind a proxy, ensure Nix proxy settings are configured

Lock File Missing or Corrupted

Symptom: error: getting status of flake.lock: No such file or directory

Solution:

# Generate a new lock file
nix flake lock

# Or reinitialize the project
flk init --force

Shell Hook Not Working

Symptom: switch and refresh commands not available after activating.

Solution:

  1. Ensure the hook is in your shell profile:
    # For bash (~/.bashrc)
    eval "$(flk hook bash)"
    
    # For zsh (~/.zshrc)
    eval "$(flk hook zsh)"
    
    # For fish (~/.config/fish/config.fish)
    flk hook fish | source
    
  2. Restart your terminal or source your profile
  3. Verify with type switch - it should show a function definition

Direnv Not Loading Environment

Symptom: Environment doesn’t activate when entering project directory.

Solution:

  1. Initialize direnv integration: flk direnv init
  2. Allow the .envrc file: direnv allow
  3. Ensure direnv hook is in your shell profile
  4. Check .envrc exists and contains use flake

Package Not Found

Symptom: flk add <package> fails with β€œpackage not found”.

Solution:

  1. Search for the correct package name: flk search <term>
  2. For deep search with versions: flk deep-search <package>
  3. Package names in Nix may differ from common names (e.g., ripgrep not rg)

Profile Errors

Symptom: β€œProfile not found” or profile-related errors.

Solution:

  1. List available profiles: flk list profiles
  2. Check .flk/profiles/ directory exists
  3. Ensure profile names contain only alphanumeric characters, dashes, and underscores

Activation Fails

Symptom: flk activate or nix develop fails with evaluation errors.

Solution:

  1. Check for syntax errors in .flk/profiles/*.nix files
  2. Validate the flake: nix flake check
  3. Try updating inputs: flk update
  4. Check the error message for specific package or syntax issues

Container Export Issues

Symptom: flk export --format docker fails.

Solution:

  1. Ensure Docker/Podman is installed and running
  2. Check you have permissions to run container commands
  3. For Docker: docker info should succeed
  4. For Podman: podman info should succeed

FAQ

General

What is flk?
flk is a CLI tool that simplifies working with Nix flake development environments. It provides commands for managing packages, environment variables, and custom commands without manually editing Nix files.

Does flk work without Nix installed?
No, Nix with flakes enabled is required. However, you can export your environment to Docker/Podman containers using flk export --format docker for systems without Nix.

What Nix version do I need?
Any recent Nix version (2.4+) with experimental features nix-command and flakes enabled.

Environment Management

How do I enable auto-switching between projects?
Add the hook to your shell profile:

# Bash
eval "$(flk hook bash)"

# Zsh
eval "$(flk hook zsh)"

# Fish
flk hook fish | source

Then use switch to reload after changes and refresh to re-enter the environment.

How do I pin a package to a specific version?
Use the --version flag:

flk add ripgrep --version 14.1.0

This stores version information in .flk/pins.nix and locks the nixpkgs commit that contains that version.

Can I have multiple profiles in one project?
Yes! Profiles are stored in .flk/profiles/. You can create additional profiles and switch between them. The default profile is set in .flk/default.nix.

How do I see what’s currently installed?

flk list             # List packages
flk command list     # List custom commands
flk env list         # List environment variables
flk show             # Show full flake configuration

Updates and Lock Files

Can I preview updates before applying?
Yes, use flk update --show which shows the diff and then restores the original lockfile.

How do I restore a previous lockfile?
Backups are stored in .flk/backups/. Restore with:

flk lock restore <backup-name>

What happens when I run flk update?
It creates a backup of your current lockfile, runs nix flake update, and shows you what changed.

Integration

Can I use flk with direnv?
Yes! Initialize with flk direnv init to create a .envrc file, then run direnv allow. Your environment will automatically load when entering the project directory.

Does flk support VS Code / other editors?
flk works with any editor. For VS Code with direnv, install the direnv extension and initialize flk direnv integration. The environment will be available in integrated terminals.

Can I export my environment to a container?
Yes:

flk export --format docker   # Creates a Docker image
flk export --format podman   # Creates a Podman image
flk export --format json     # Exports config as JSON

Troubleshooting

Why can’t flk find my package?
Package names in Nix may differ from common names. Use flk search <term> to find the correct name, or flk deep-search <package> for detailed info including available versions.

Why isn’t my shell hook working?
Ensure you’ve added the hook to your shell profile and restarted your terminal. The switch and refresh commands are only available inside an activated flk environment.

Contributing

Contributing to CONTRIBUTING.md

First off, thanks for taking the time to contribute! ❀️

All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. πŸŽ‰

And if you like the project, but just don’t have time to contribute, that’s fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:

  • Star the project
  • Tweet about it
  • Refer this project in your project’s readme
  • Mention the project at local meetups and tell your friends/colleagues

Table of Contents

Code of Conduct

This project and everyone participating in it is governed by the CONTRIBUTING.md Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <>.

I Have a Question

If you want to ask a question, we assume that you have read the available Documentation.

Before you ask a question, it is best to search for existing Issues that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.

If you then still feel the need to ask a question and need clarification, we recommend the following:

  • Open an Issue.
  • Provide as much context as you can about what you’re running into.
  • Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.

We will then take care of the issue as soon as possible.

I Want To Contribute

When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.

Reporting Bugs

Before Submitting a Bug Report

A good bug report shouldn’t leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.

  • Make sure that you are using the latest version.
  • Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the documentation. If you are looking for support, you might want to check this section).
  • To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the bug tracker.
  • Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
  • Collect information about the bug:
  • Stack trace (Traceback)
  • OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
  • Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
  • Possibly your input and the output
  • Can you reliably reproduce the issue? And can you also reproduce it with older versions?

How Do I Submit a Good Bug Report?

You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.

We use GitHub issues to track bugs and errors. If you run into an issue with the project:

  • Open an Issue. (Since we can’t be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
  • Explain the behavior you would expect and the actual behavior.
  • Please provide as much context as possible and describe the reproduction steps that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
  • Provide the information you collected in the previous section.

Once it’s filed:

  • The project team will label the issue accordingly.
  • A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as needs-repro. Bugs with the needs-repro tag will not be addressed until they are reproduced.
  • If the team is able to reproduce the issue, it will be marked needs-fix, as well as possibly other tags (such as critical), and the issue will be left to be implemented by someone.

Suggesting Enhancements

This section guides you through submitting an enhancement suggestion for CONTRIBUTING.md, including completely new features and minor improvements to existing functionality. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.

Before Submitting an Enhancement

  • Make sure that you are using the latest version.
  • Read the documentation carefully and find out if the functionality is already covered, maybe by an individual configuration.
  • Perform a search to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
  • Find out whether your idea fits with the scope and aims of the project. It’s up to you to make a strong case to convince the project’s developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you’re just targeting a minority of users, consider writing an add-on/plugin library.

How Do I Submit a Good Enhancement Suggestion?

Enhancement suggestions are tracked as GitHub issues.

  • Use a clear and descriptive title for the issue to identify the suggestion.
  • Provide a step-by-step description of the suggested enhancement in as many details as possible.
  • Describe the current behavior and explain which behavior you expected to see instead and why. At this point you can also tell which alternatives do not work for you.
  • You may want to include screenshots and animated GIFs which help you demonstrate the steps or point out the part which the suggestion is related to. You can use this tool to record GIFs on macOS and Windows, and this tool or this tool on Linux.
  • Explain why this enhancement would be useful to most CONTRIBUTING.md users. You may also want to point out the other projects that solved it better and which could serve as inspiration.

Commit Messages

All commit messages in this repo shall follow the Conventional commit guidelines

Attribution

This guide is based on the contributing.md. Make your own!

Code of Conduct

Contributor Covenant Code of Conduct

Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

Our Standards

Examples of behavior that contributes to creating a positive environment include:

  • Using welcoming and inclusive language
  • Being respectful of differing viewpoints and experiences
  • Gracefully accepting constructive criticism
  • Focusing on what is best for the community
  • Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

  • The use of sexualized language or imagery and unwelcome sexual attention or advances
  • Trolling, insulting/derogatory comments, and personal or political attacks
  • Public or private harassment
  • Publishing others’ private information, such as a physical or electronic address, without explicit permission
  • Other conduct which could reasonably be considered inappropriate in a professional setting

Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at development@pixlracks.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.

Attribution

This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

Development Setup

This guide helps you set up a development environment for contributing to flk.

Requirements

  • Nix with flakes enabled (Lix or Determinate installer recommended)
  • Rust toolchain (1.70+ recommended)
  • Git for version control

Quick Start with Nix

The easiest way to get started is using flk’s own flake:

git clone https://github.com/AEduardo-dev/flk.git
cd flk
nix develop

This provides all required tools including Rust, cargo, and testing dependencies.

Building from Source

# Clone the repository
git clone https://github.com/AEduardo-dev/flk.git
cd flk

# Debug build (faster compilation)
cargo build

# Release build (optimized)
cargo build --release

# The binary is at target/release/flk

Running Tests

# Run all tests
cargo test

# Run a specific test
cargo test test_add_package

# Run tests with output
cargo test -- --nocapture

Linting and Formatting

# Check formatting
cargo fmt --all -- --check

# Apply formatting
cargo fmt --all

# Run clippy lints
cargo clippy -- -D warnings

Running the CLI Locally

During development, use cargo run:

# Run flk commands
cargo run -- init --template rust
cargo run -- add ripgrep
cargo run -- list packages

# With release optimizations (faster execution)
cargo run --release -- search git

For shell integration while iterating:

# Build and install locally
cargo install --path .

# Or add an alias
alias flk="cargo run --release --"

Building Documentation

API Documentation (cargo doc)

# Generate and open API docs
cargo doc --no-deps --open

# Check for documentation warnings
cargo doc --no-deps 2>&1 | grep warning

User Guide (mdbook)

# Install mdbook if needed
cargo install mdbook

# Serve the book locally (auto-reloads)
cd flk-book
mdbook serve
# Open http://localhost:3000

# Build static HTML
mdbook build
# Output in flk-book/book/

Combined Documentation

The Nix flake can build both:

nix build .#docs
# Output in result/

Project Structure

flk/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.rs          # CLI entrypoint
β”‚   β”œβ”€β”€ lib.rs           # Library exports
β”‚   β”œβ”€β”€ commands/        # CLI command handlers
β”‚   β”œβ”€β”€ flake/           # Flake generation and parsing
β”‚   β”‚   β”œβ”€β”€ generator.rs # Template instantiation
β”‚   β”‚   β”œβ”€β”€ parsers/     # Nix file parsers
β”‚   β”‚   └── interfaces/  # Data structures
β”‚   β”œβ”€β”€ nix/             # Nix command wrappers
β”‚   └── utils/           # Helpers (backup, visual)
β”œβ”€β”€ templates/           # Nix templates (embedded at compile time)
β”œβ”€β”€ tests/               # Integration tests
β”œβ”€β”€ flk-book/            # mdbook documentation
└── flake.nix            # Nix flake for development

Testing Changes

Before submitting a PR:

# Run the full test suite
cargo test

# Check formatting and lints
cargo fmt --all -- --check
cargo clippy -- -D warnings

# Build documentation without warnings
cargo doc --no-deps

# Test the binary manually
cargo run -- init --template rust
cargo run -- add ripgrep
cargo run -- list packages

Debugging

For verbose output during development:

# Enable Rust backtraces
RUST_BACKTRACE=1 cargo run -- add ripgrep

# Debug Nix commands
RUST_LOG=debug cargo run -- search git