From 49bb6ea08deeae48ba64dc28241bc0c88e8fe5a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:29:07 +0000 Subject: [PATCH 01/28] Initial plan From 9221e60d0fc96fa7c23471b9a956eeb379a365cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:32:20 +0000 Subject: [PATCH 02/28] Add Nix flake, .envrc, and update documentation Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- .envrc | 1 + .gitignore | 3 ++ CONTRIBUTING.md | 72 ++++++++++++++++++++++++++++-- README.md | 18 ++++++++ flake.nix | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 .envrc create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 323bd21d..c03b5bbe 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,9 @@ dmypy.json *~ .DS_Store +# direnv +.direnv/ + # Jupyter Notebook .ipynb_checkpoints diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c77b743..b44e14b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,6 +19,8 @@ Thank you for your interest in contributing to DeepWork! This guide will help yo - **Python 3.11 or higher** - Required for running DeepWork - **Git** - For version control - **Nix** (optional but recommended) - For reproducible development environment + - Nix flakes enabled (add `experimental-features = nix-command flakes` to `~/.config/nix/nix.conf`) +- **direnv** (optional) - For automatic environment activation when using Nix flakes - **uv** - Modern Python package installer (included in Nix environment) - **Signed CLA** - All contributors must sign the Contributor License Agreement (see below) @@ -61,9 +63,62 @@ For the full text, see [CLA.md](CLA/version_1/CLA.md). ## Development Setup -### Option 1: Using Nix (Recommended) +### Setting Up direnv (Optional but Recommended) -The easiest way to get started is using Nix, which provides a fully reproducible development environment with all dependencies pre-configured. +direnv automatically loads the Nix environment when you `cd` into the project directory: + +```bash +# Install direnv (if not already installed) +# On macOS with Homebrew: +brew install direnv + +# On Linux (Debian/Ubuntu): +apt-get install direnv + +# On NixOS or with Nix: +nix-env -i direnv + +# Add direnv hook to your shell +# For bash, add to ~/.bashrc: +eval "$(direnv hook bash)" + +# For zsh, add to ~/.zshrc: +eval "$(direnv hook zsh)" + +# For fish, add to ~/.config/fish/config.fish: +direnv hook fish | source + +# Restart your shell or source your rc file +source ~/.bashrc # or ~/.zshrc +``` + +Once direnv is set up, the environment will activate automatically when you enter the directory. + +### Option 1: Using Nix Flakes (Recommended) + +The easiest way to get started is using Nix flakes, which provides a fully reproducible development environment with all dependencies pre-configured. + +#### Quick Start with direnv (Automatic) + +If you have direnv installed, the environment will activate automatically: + +```bash +# Clone the repository +git clone https://github.com/deepwork/deepwork.git +cd deepwork + +# Allow direnv (first time only) +direnv allow + +# Environment activates automatically! +# You'll see the DeepWork welcome message +``` + +The `.envrc` file configures direnv to use the Nix flake, so you'll automatically enter the development environment whenever you `cd` into the directory. + +#### Manual Flake Usage + +If you don't use direnv, you can manually enter the development environment: ```bash # Clone the repository @@ -71,15 +126,26 @@ git clone https://github.com/deepwork/deepwork.git cd deepwork # Enter the Nix development environment +nix develop +``` + +#### Legacy Support (shell.nix) + +For compatibility, `shell.nix` is still available: + +```bash nix-shell ``` -When you enter `nix-shell`, you'll see a welcome message with available tools. The environment includes: +#### What's Included + +When you enter the Nix environment (via flake or shell.nix), you'll see a welcome message with available tools. The environment includes: - Python 3.11 - uv (package manager) - pytest, ruff, mypy - All Python dependencies - Environment variables (`PYTHONPATH`, `DEEPWORK_DEV=1`) +- Automatic virtual environment activation ### Option 2: Manual Setup (Without Nix) diff --git a/README.md b/README.md index 0d6c7bfd..50d77c37 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,24 @@ your-project/ - **[Architecture](doc/architecture.md)**: Complete design specification - **[Contributing](CONTRIBUTING.md)**: Setup development environment and contribute +## Development with Nix + +DeepWork is available as a Nix flake for reproducible development environments: + +```bash +# Using Nix flakes +nix develop + +# Or with direnv (automatic activation) +echo "use flake" > .envrc +direnv allow + +# Legacy Nix shell +nix-shell +``` + +The Nix environment provides all dependencies including Python 3.11, uv, pytest, ruff, and mypy. + ## Project Structure ``` diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..494f6486 --- /dev/null +++ b/flake.nix @@ -0,0 +1,114 @@ +{ + description = "DeepWork - Framework for enabling AI agents to perform complex, multi-step work tasks"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + }; + in + { + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + # Python 3.11 or later + python311 + python311Packages.pip + python311Packages.virtualenv + + # Modern Python tooling + uv + + # Git for version control + git + + # Additional tools + jq # For JSON processing + + # Python development dependencies + python311Packages.jinja2 + python311Packages.pyyaml + python311Packages.gitpython + python311Packages.pytest + python311Packages.pytest-mock + python311Packages.pytest-cov + python311Packages.click + python311Packages.rich + + # Linting and type checking + ruff + mypy + ]; + + shellHook = '' + # Set up environment variables + export PYTHONPATH="$PWD/src:$PYTHONPATH" + export DEEPWORK_DEV=1 + + # Auto-sync dependencies and activate venv for direct deepwork access + echo "Setting up DeepWork development environment..." + uv sync --quiet 2>/dev/null || uv sync + + # Activate the virtual environment so 'deepwork' command is directly available + if [ -f .venv/bin/activate ]; then + source .venv/bin/activate + fi + + echo "" + echo "DeepWork Development Environment" + echo "================================" + echo "" + echo "Python version: $(python --version)" + echo "uv version: $(uv --version)" + echo "" + echo "Available tools:" + echo " - deepwork: CLI is ready (try 'deepwork --help')" + echo " - pytest: Testing framework" + echo " - ruff: Python linter and formatter" + echo " - mypy: Static type checker" + echo "" + echo "Quick start:" + echo " - 'deepwork --help' to see available commands" + echo " - 'pytest' to run tests" + echo " - Read doc/architecture.md for design details" + echo "" + ''; + }; + + # Make the package available as a flake output + packages.default = pkgs.python311Packages.buildPythonPackage { + pname = "deepwork"; + version = "0.3.0"; + src = ./.; + format = "pyproject"; + + nativeBuildInputs = with pkgs.python311Packages; [ + hatchling + ]; + + propagatedBuildInputs = with pkgs.python311Packages; [ + jinja2 + pyyaml + gitpython + click + rich + jsonschema + ]; + + # Skip tests during build (they can be run in devShell) + doCheck = false; + + meta = with pkgs.lib; { + description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; + homepage = "https://github.com/deepwork/deepwork"; + license = licenses.unfree; # Business Source License 1.1 + }; + }; + } + ); +} From 1e4586ebb9ae9b197baa50a9732fc3d918e381d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:33:36 +0000 Subject: [PATCH 03/28] Enhance flake with apps output and improve README Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- README.md | 15 ++++++++++++++ flake.nix | 60 +++++++++++++++++++++++++++++++------------------------ 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 50d77c37..1a705838 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,21 @@ nix-shell The Nix environment provides all dependencies including Python 3.11, uv, pytest, ruff, and mypy. +### Installing DeepWork from Flake + +You can also install deepwork directly from the flake: + +```bash +# Install deepwork from this flake +nix profile install github:Unsupervisedcom/deepwork + +# Or run it without installing +nix run github:Unsupervisedcom/deepwork -- --help + +# Or build the package +nix build github:Unsupervisedcom/deepwork +``` + ## Project Structure ``` diff --git a/flake.nix b/flake.nix index 494f6486..6b82df44 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,34 @@ pkgs = import nixpkgs { inherit system; }; + deepwork = pkgs.python311Packages.buildPythonPackage { + pname = "deepwork"; + version = "0.3.0"; + src = ./.; + format = "pyproject"; + + nativeBuildInputs = with pkgs.python311Packages; [ + hatchling + ]; + + propagatedBuildInputs = with pkgs.python311Packages; [ + jinja2 + pyyaml + gitpython + click + rich + jsonschema + ]; + + # Skip tests during build (they can be run in devShell) + doCheck = false; + + meta = with pkgs.lib; { + description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; + homepage = "https://github.com/Unsupervisedcom/deepwork"; + license = licenses.unfree; # Business Source License 1.1 + }; + }; in { devShells.default = pkgs.mkShell { @@ -81,33 +109,13 @@ }; # Make the package available as a flake output - packages.default = pkgs.python311Packages.buildPythonPackage { - pname = "deepwork"; - version = "0.3.0"; - src = ./.; - format = "pyproject"; - - nativeBuildInputs = with pkgs.python311Packages; [ - hatchling - ]; - - propagatedBuildInputs = with pkgs.python311Packages; [ - jinja2 - pyyaml - gitpython - click - rich - jsonschema - ]; - - # Skip tests during build (they can be run in devShell) - doCheck = false; + packages.default = deepwork; + packages.deepwork = deepwork; - meta = with pkgs.lib; { - description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; - homepage = "https://github.com/deepwork/deepwork"; - license = licenses.unfree; # Business Source License 1.1 - }; + # Make deepwork runnable with 'nix run' + apps.default = { + type = "app"; + program = "${deepwork}/bin/deepwork"; }; } ); From d6b5774014e72da148f409dfae9523476ffeea38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:34:26 +0000 Subject: [PATCH 04/28] Add comprehensive Nix flake documentation Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- README.md | 1 + doc/nix-flake.md | 266 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 doc/nix-flake.md diff --git a/README.md b/README.md index 1a705838..1df8263b 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,7 @@ your-project/ - **[Architecture](doc/architecture.md)**: Complete design specification - **[Contributing](CONTRIBUTING.md)**: Setup development environment and contribute +- **[Nix Flakes Guide](doc/nix-flake.md)**: Comprehensive guide for using DeepWork with Nix flakes ## Development with Nix diff --git a/doc/nix-flake.md b/doc/nix-flake.md new file mode 100644 index 00000000..d01808fc --- /dev/null +++ b/doc/nix-flake.md @@ -0,0 +1,266 @@ +# Using DeepWork with Nix Flakes + +DeepWork provides a Nix flake for reproducible development environments and easy installation. This document covers how to use the flake in various scenarios. + +## Prerequisites + +- Nix with flakes support enabled +- Add to your `~/.config/nix/nix.conf`: + ``` + experimental-features = nix-command flakes + ``` + +## Development Environment + +### Quick Start with direnv (Recommended) + +direnv automatically activates the Nix environment when you enter the directory: + +```bash +# Clone the repository +git clone https://github.com/Unsupervisedcom/deepwork.git +cd deepwork + +# Allow direnv to load the environment +direnv allow + +# Environment activates automatically! +``` + +The `.envrc` file is already configured with `use flake`, so you'll get: +- Python 3.11 +- uv package manager +- All development dependencies (pytest, ruff, mypy) +- Automatic virtual environment activation +- Environment variables set (`PYTHONPATH`, `DEEPWORK_DEV=1`) + +### Manual Activation + +If you don't use direnv: + +```bash +# Enter development shell +nix develop + +# Or use the legacy command +nix-shell +``` + +### What's Included + +The development environment provides: + +- **Python 3.11** with pip and virtualenv +- **uv** - Fast Python package installer +- **Git** - Version control +- **jq** - JSON processing +- **Python packages**: + - jinja2, pyyaml, gitpython + - pytest, pytest-mock, pytest-cov + - click, rich +- **Development tools**: + - ruff - Python linter and formatter + - mypy - Static type checker + +## Installing DeepWork + +### From the Flake + +Install deepwork system-wide or in your user profile: + +```bash +# Install to your user profile +nix profile install github:Unsupervisedcom/deepwork + +# Verify installation +deepwork --help +``` + +### Running Without Installing + +```bash +# Run deepwork directly +nix run github:Unsupervisedcom/deepwork -- --help + +# Run a specific command +nix run github:Unsupervisedcom/deepwork -- install --platform claude +``` + +### Building the Package + +```bash +# Build the package +nix build github:Unsupervisedcom/deepwork + +# Result will be in ./result/ +ls -la result/bin/deepwork +``` + +## Using in Your Project + +### As a Development Dependency + +Create a `flake.nix` in your project that uses DeepWork: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + deepwork.url = "github:Unsupervisedcom/deepwork"; + }; + + outputs = { self, nixpkgs, deepwork }: + let + system = "x86_64-linux"; # or your system + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + buildInputs = [ + deepwork.packages.${system}.default + ]; + }; + }; +} +``` + +### As a Runtime Dependency + +If you're building a Nix package that depends on DeepWork: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + deepwork.url = "github:Unsupervisedcom/deepwork"; + }; + + outputs = { self, nixpkgs, deepwork }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + packages.${system}.default = pkgs.stdenv.mkDerivation { + name = "my-project"; + buildInputs = [ + deepwork.packages.${system}.default + ]; + }; + }; +} +``` + +## Flake Outputs + +The flake provides several outputs: + +### devShells.default + +Development environment with all tools and dependencies. + +```bash +nix develop +``` + +### packages.default / packages.deepwork + +The deepwork Python package. + +```bash +nix build +nix build .#deepwork +``` + +### apps.default + +Runnable deepwork application. + +```bash +nix run +nix run .#default -- --help +``` + +## Updating Dependencies + +### Update nixpkgs + +```bash +# Update the flake lock file +nix flake update + +# Or update just nixpkgs +nix flake lock --update-input nixpkgs +``` + +### Update Python Dependencies + +Python dependencies are managed by `uv` and `pyproject.toml`: + +```bash +# Inside the development environment +nix develop +uv sync +``` + +## Troubleshooting + +### Flakes Not Enabled + +If you get an error about flakes not being recognized: + +```bash +# Add to ~/.config/nix/nix.conf +echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf +``` + +### direnv Not Working + +1. Make sure direnv is installed: + ```bash + nix-env -i direnv + ``` + +2. Add the hook to your shell rc file: + ```bash + # For bash (~/.bashrc) + eval "$(direnv hook bash)" + + # For zsh (~/.zshrc) + eval "$(direnv hook zsh)" + ``` + +3. Allow the directory: + ```bash + direnv allow + ``` + +### Environment Variables Not Set + +If `PYTHONPATH` or `DEEPWORK_DEV` are not set: + +```bash +# Manually source the hook +source .envrc +``` + +Or ensure you're in the Nix environment: + +```bash +nix develop +``` + +## Backward Compatibility + +The `shell.nix` file is still maintained for users who prefer the traditional approach: + +```bash +nix-shell +``` + +This provides the same environment as `nix develop`, just using the legacy interface. + +## Additional Resources + +- [Nix Flakes Documentation](https://nixos.wiki/wiki/Flakes) +- [direnv Documentation](https://direnv.net/) +- [DeepWork Contributing Guide](../CONTRIBUTING.md) +- [DeepWork Architecture](./architecture.md) From 78685a0971727c40d7c783cc4d52cce8e75ef12e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:37:00 +0000 Subject: [PATCH 05/28] Fix license definition and improve uv sync logic in flake Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- flake.nix | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 6b82df44..e4f29aa4 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,12 @@ meta = with pkgs.lib; { description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; homepage = "https://github.com/Unsupervisedcom/deepwork"; - license = licenses.unfree; # Business Source License 1.1 + # Business Source License 1.1 - not OSI approved + license = { + fullName = "Business Source License 1.1"; + url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; + free = false; + }; }; }; in @@ -80,7 +85,10 @@ # Auto-sync dependencies and activate venv for direct deepwork access echo "Setting up DeepWork development environment..." - uv sync --quiet 2>/dev/null || uv sync + if ! uv sync --quiet 2>/dev/null; then + echo "Running uv sync..." + uv sync + fi # Activate the virtual environment so 'deepwork' command is directly available if [ -f .venv/bin/activate ]; then From ee58c56493d21c97acddab7b09173e90d4f8383b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:38:00 +0000 Subject: [PATCH 06/28] Add missing jsonschema to development environment Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index e4f29aa4..c3e7380f 100644 --- a/flake.nix +++ b/flake.nix @@ -72,6 +72,7 @@ python311Packages.pytest-cov python311Packages.click python311Packages.rich + python311Packages.jsonschema # Linting and type checking ruff From 874270884579ad9403ec6807d44509e6e0905837 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:55:33 +0000 Subject: [PATCH 07/28] Enhance documentation with explicit GitHub flake reference examples Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- doc/nix-flake.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/doc/nix-flake.md b/doc/nix-flake.md index d01808fc..d924a0d8 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -98,14 +98,17 @@ ls -la result/bin/deepwork ## Using in Your Project +DeepWork can be added to your existing Nix flake using a GitHub reference. This allows you to use DeepWork in your development environment or as a dependency for your projects. + ### As a Development Dependency -Create a `flake.nix` in your project that uses DeepWork: +Create a `flake.nix` in your project that references DeepWork via GitHub: ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Add DeepWork via GitHub reference deepwork.url = "github:Unsupervisedcom/deepwork"; }; @@ -123,6 +126,34 @@ Create a `flake.nix` in your project that uses DeepWork: } ``` +You can also pin to a specific version, tag, or commit: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Pin to a specific tag + deepwork.url = "github:Unsupervisedcom/deepwork/0.3.0"; + # Or pin to a specific commit + # deepwork.url = "github:Unsupervisedcom/deepwork/abc1234"; + # Or pin to a specific branch + # deepwork.url = "github:Unsupervisedcom/deepwork/main"; + }; + + outputs = { self, nixpkgs, deepwork }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + buildInputs = [ + deepwork.packages.${system}.default + ]; + }; + }; +} +``` + ### As a Runtime Dependency If you're building a Nix package that depends on DeepWork: @@ -131,6 +162,7 @@ If you're building a Nix package that depends on DeepWork: { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Add DeepWork as a dependency via GitHub reference deepwork.url = "github:Unsupervisedcom/deepwork"; }; @@ -149,6 +181,83 @@ If you're building a Nix package that depends on DeepWork: } ``` +### Using with flake-utils for Multi-System Support + +For projects that need to support multiple systems (Linux, macOS, etc.): + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + # Add DeepWork via GitHub reference + deepwork.url = "github:Unsupervisedcom/deepwork"; + }; + + outputs = { self, nixpkgs, flake-utils, deepwork }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in { + devShells.default = pkgs.mkShell { + buildInputs = [ + deepwork.packages.${system}.default + ]; + }; + } + ); +} +``` + +### Complete Example with direnv + +Create a complete development environment with DeepWork and direnv: + +**flake.nix:** +```nix +{ + description = "My project using DeepWork"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # Reference DeepWork from GitHub + deepwork.url = "github:Unsupervisedcom/deepwork"; + }; + + outputs = { self, nixpkgs, deepwork }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + buildInputs = [ + # Include DeepWork in the development environment + deepwork.packages.${system}.default + # Add other dependencies + pkgs.python311 + pkgs.git + ]; + + shellHook = '' + echo "DeepWork is available!" + deepwork --version + ''; + }; + }; +} +``` + +**.envrc:** +```bash +use flake +``` + +Then run: +```bash +direnv allow +# Environment with DeepWork loads automatically +``` + ## Flake Outputs The flake provides several outputs: From 2a77af0da9a86ec2b5bb67fa3d96afc65ede6913 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 07:36:40 +0000 Subject: [PATCH 08/28] Update validate workflow to use Nix development shell Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- .github/workflows/validate.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index a463b777..12e51ef8 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -18,23 +18,21 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install uv - uses: astral-sh/setup-uv@v4 + - name: Install Nix + uses: cachix/install-nix-action@v31 with: - version: "latest" + nix_path: nixpkgs=channel:nixos-unstable - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" + - name: Setup Nix development environment + uses: nicknovitski/nix-develop@v1 - - name: Install dependencies + - name: Install Python dependencies run: uv sync --extra dev - name: Check formatting (ruff) run: | - uv run ruff format --check src/ tests/ - uv run ruff check src/ tests/ + ruff format --check src/ tests/ + ruff check src/ tests/ - name: Run tests - run: uv run pytest tests/ -v + run: pytest tests/ -v From 785e18964d47d476c34c1c7e3bd84f97e67b2b98 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:06:40 +0000 Subject: [PATCH 09/28] Add build job to validate flake package can be built Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- .github/workflows/validate.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 12e51ef8..66e28174 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -36,3 +36,22 @@ jobs: - name: Run tests run: pytest tests/ -v + + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Build deepwork package + run: nix build .#deepwork + + - name: Verify package output + run: | + ls -la result/bin/deepwork + ./result/bin/deepwork --version From 1440713b9b7874af1e638e941310820fb7e98a1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:08:18 +0000 Subject: [PATCH 10/28] Simplify Nix configuration in validate workflow Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- .github/workflows/validate.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 66e28174..aa131ede 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -20,8 +20,6 @@ jobs: - name: Install Nix uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - name: Setup Nix development environment uses: nicknovitski/nix-develop@v1 @@ -45,11 +43,9 @@ jobs: - name: Install Nix uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - name: Build deepwork package - run: nix build .#deepwork + run: nix build - name: Verify package output run: | From 30906f0c843140077455f1059c0034bb2f7ec887 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 15:19:49 +0000 Subject: [PATCH 11/28] Consolidate build into tests job after pytest Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- .github/workflows/validate.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index aa131ede..26a6ddf8 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -35,15 +35,6 @@ jobs: - name: Run tests run: pytest tests/ -v - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Install Nix - uses: cachix/install-nix-action@v31 - - name: Build deepwork package run: nix build From 82f2b9c2c6706b2114a1bef2abb93d59f183386e Mon Sep 17 00:00:00 2001 From: Nicholas Romero Date: Mon, 19 Jan 2026 09:29:55 -0600 Subject: [PATCH 12/28] chore: --- flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ uv.lock | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 flake.lock diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..5a9df819 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1768564909, + "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/uv.lock b/uv.lock index 564a99f6..c4091ca4 100644 --- a/uv.lock +++ b/uv.lock @@ -126,7 +126,7 @@ toml = [ [[package]] name = "deepwork" -version = "0.5.0" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "click" }, From e24cea877286b1eea5e42ecfab19cf6d66e2a5ba Mon Sep 17 00:00:00 2001 From: Nicholas Romero Date: Mon, 19 Jan 2026 11:59:28 -0600 Subject: [PATCH 13/28] chore: allow unfree packages in nixpkgs for BSL 1.1 license --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index c3e7380f..6ab17be6 100644 --- a/flake.nix +++ b/flake.nix @@ -11,6 +11,8 @@ let pkgs = import nixpkgs { inherit system; + # Allow unfree packages to support the Business Source License 1.1 + config.allowUnfree = true; }; deepwork = pkgs.python311Packages.buildPythonPackage { pname = "deepwork"; From 3d722e4c87a08defe63bbc4690aeeda3182972c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 20:17:49 +0000 Subject: [PATCH 14/28] Fix Nix flake package to include Python with deepwork in PYTHONPATH Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- doc/nix-flake.md | 45 +++++++++++++++++++++++ flake.nix | 92 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 115 insertions(+), 22 deletions(-) diff --git a/doc/nix-flake.md b/doc/nix-flake.md index d924a0d8..16339823 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -321,6 +321,51 @@ If you get an error about flakes not being recognized: echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf ``` +### Hooks Not Finding DeepWork Module + +When using DeepWork from a Nix flake in your project, hooks may fail with "No module named 'deepwork'" because they run outside of `nix develop`. The flake package includes wrapper scripts that solve this: + +**Solution:** + +Instead of using `python -m deepwork.hooks.rules_check` directly in hooks, use the provided wrapper commands: + +- For Claude Code: Use `deepwork-python -m deepwork.hooks.rules_check` +- For Gemini CLI: Use `deepwork-python -m deepwork.hooks.rules_check` + +Or use the dedicated hook wrappers: +- `deepwork-claude-hook deepwork.hooks.rules_check` +- `deepwork-gemini-hook deepwork.hooks.rules_check` + +These wrappers ensure the Python environment has access to the deepwork module even when running outside of the Nix development shell. + +**In your flake.nix:** + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + deepwork.url = "github:Unsupervisedcom/deepwork"; + }; + + outputs = { self, nixpkgs, deepwork }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { inherit system; }; + in { + devShells.${system}.default = pkgs.mkShell { + buildInputs = [ + deepwork.packages.${system}.default + ]; + + # Optional: Add deepwork binaries to PATH for easier hook usage + shellHook = '' + export PATH="${deepwork.packages.${system}.default}/bin:$PATH" + ''; + }; + }; +} +``` + ### direnv Not Working 1. Make sure direnv is installed: diff --git a/flake.nix b/flake.nix index 6ab17be6..4148ffc8 100644 --- a/flake.nix +++ b/flake.nix @@ -11,35 +11,83 @@ let pkgs = import nixpkgs { inherit system; - # Allow unfree packages to support the Business Source License 1.1 - config.allowUnfree = true; }; - deepwork = pkgs.python311Packages.buildPythonPackage { - pname = "deepwork"; - version = "0.3.0"; + + # Create a wrapped Python environment with deepwork available + pythonWithDeepwork = pkgs.python311.withPackages (ps: [ + (ps.buildPythonPackage { + pname = "deepwork"; + version = "0.3.0"; + src = ./.; + format = "pyproject"; + + nativeBuildInputs = with ps; [ + hatchling + ]; + + propagatedBuildInputs = with ps; [ + jinja2 + pyyaml + gitpython + click + rich + jsonschema + ]; + + # Skip tests during build (they can be run in devShell) + doCheck = false; + + meta = with pkgs.lib; { + description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; + homepage = "https://github.com/Unsupervisedcom/deepwork"; + # Business Source License 1.1 - not OSI approved + license = { + fullName = "Business Source License 1.1"; + url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; + free = false; + }; + }; + }) + ]); + + # Create the main deepwork package with proper wrappers + deepwork = pkgs.stdenv.mkDerivation { + name = "deepwork-0.3.0"; src = ./.; - format = "pyproject"; - - nativeBuildInputs = with pkgs.python311Packages; [ - hatchling - ]; - - propagatedBuildInputs = with pkgs.python311Packages; [ - jinja2 - pyyaml - gitpython - click - rich - jsonschema - ]; - # Skip tests during build (they can be run in devShell) - doCheck = false; + nativeBuildInputs = [ pkgs.makeWrapper ]; + + buildPhase = '' + # Nothing to build, we just need to wrap the Python package + ''; + + installPhase = '' + mkdir -p $out/bin + + # Create wrapper for deepwork CLI + makeWrapper ${pythonWithDeepwork}/bin/deepwork $out/bin/deepwork \ + --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" + + # Create wrapper scripts for claude hook + makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-claude-hook \ + --add-flags "-m" \ + --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" \ + --set DEEPWORK_HOOK_PLATFORM "claude" + + # Create wrapper scripts for gemini hook + makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-gemini-hook \ + --add-flags "-m" \ + --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" \ + --set DEEPWORK_HOOK_PLATFORM "gemini" + + # Also create a python wrapper that has deepwork in PYTHONPATH + makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-python \ + --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" + ''; meta = with pkgs.lib; { description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; homepage = "https://github.com/Unsupervisedcom/deepwork"; - # Business Source License 1.1 - not OSI approved license = { fullName = "Business Source License 1.1"; url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; From 829c16778f9f2bca631f6b2830f09a4fba9b3a39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:43:04 +0000 Subject: [PATCH 15/28] Add deepwork hook CLI command for cleaner hook invocation Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- doc/nix-flake.md | 59 ++++++++------------ flake.nix | 92 ++++++++----------------------- src/deepwork/cli/hook.py | 69 +++++++++++++++++++++++ src/deepwork/cli/main.py | 2 + src/deepwork/hooks/__init__.py | 14 +++-- src/deepwork/hooks/claude_hook.sh | 30 +++++----- src/deepwork/hooks/gemini_hook.sh | 30 +++++----- src/deepwork/hooks/rules_check.py | 13 +++-- 8 files changed, 159 insertions(+), 150 deletions(-) create mode 100644 src/deepwork/cli/hook.py diff --git a/doc/nix-flake.md b/doc/nix-flake.md index 16339823..d7d46282 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -321,50 +321,35 @@ If you get an error about flakes not being recognized: echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf ``` -### Hooks Not Finding DeepWork Module +### Hooks Working with Different Installation Methods -When using DeepWork from a Nix flake in your project, hooks may fail with "No module named 'deepwork'" because they run outside of `nix develop`. The flake package includes wrapper scripts that solve this: +DeepWork hooks use the `deepwork hook` CLI command, which works consistently regardless of how deepwork was installed: -**Solution:** +**Installation Methods Supported:** +- Nix flake (`nix profile install github:Unsupervisedcom/deepwork`) +- pipx (`pipx install deepwork`) +- uv (`uv tool install deepwork`) +- pip (`pip install deepwork`) -Instead of using `python -m deepwork.hooks.rules_check` directly in hooks, use the provided wrapper commands: +**How it Works:** -- For Claude Code: Use `deepwork-python -m deepwork.hooks.rules_check` -- For Gemini CLI: Use `deepwork-python -m deepwork.hooks.rules_check` - -Or use the dedicated hook wrappers: -- `deepwork-claude-hook deepwork.hooks.rules_check` -- `deepwork-gemini-hook deepwork.hooks.rules_check` - -These wrappers ensure the Python environment has access to the deepwork module even when running outside of the Nix development shell. +The hook wrapper scripts (`.deepwork/hooks/claude_hook.sh`, `.gemini/hooks/gemini_hook.sh`) call: +```bash +deepwork hook rules_check +``` -**In your flake.nix:** +Instead of the old approach: +```bash +python -m deepwork.hooks.rules_check # ❌ Doesn't work with all install methods +``` -```nix -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - deepwork.url = "github:Unsupervisedcom/deepwork"; - }; +**Requirements:** +1. The `deepwork` command must be in your PATH +2. For Nix flake users: Install with `nix profile install github:Unsupervisedcom/deepwork` +3. For pipx users: Install with `pipx install deepwork` +4. For uv users: Install with `uv tool install deepwork` - outputs = { self, nixpkgs, deepwork }: - let - system = "x86_64-linux"; - pkgs = import nixpkgs { inherit system; }; - in { - devShells.${system}.default = pkgs.mkShell { - buildInputs = [ - deepwork.packages.${system}.default - ]; - - # Optional: Add deepwork binaries to PATH for easier hook usage - shellHook = '' - export PATH="${deepwork.packages.${system}.default}/bin:$PATH" - ''; - }; - }; -} -``` +All these methods ensure `deepwork` is available globally, so hooks work correctly outside of development environments. ### direnv Not Working diff --git a/flake.nix b/flake.nix index 4148ffc8..6ab17be6 100644 --- a/flake.nix +++ b/flake.nix @@ -11,83 +11,35 @@ let pkgs = import nixpkgs { inherit system; + # Allow unfree packages to support the Business Source License 1.1 + config.allowUnfree = true; }; - - # Create a wrapped Python environment with deepwork available - pythonWithDeepwork = pkgs.python311.withPackages (ps: [ - (ps.buildPythonPackage { - pname = "deepwork"; - version = "0.3.0"; - src = ./.; - format = "pyproject"; - - nativeBuildInputs = with ps; [ - hatchling - ]; - - propagatedBuildInputs = with ps; [ - jinja2 - pyyaml - gitpython - click - rich - jsonschema - ]; - - # Skip tests during build (they can be run in devShell) - doCheck = false; - - meta = with pkgs.lib; { - description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; - homepage = "https://github.com/Unsupervisedcom/deepwork"; - # Business Source License 1.1 - not OSI approved - license = { - fullName = "Business Source License 1.1"; - url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; - free = false; - }; - }; - }) - ]); - - # Create the main deepwork package with proper wrappers - deepwork = pkgs.stdenv.mkDerivation { - name = "deepwork-0.3.0"; + deepwork = pkgs.python311Packages.buildPythonPackage { + pname = "deepwork"; + version = "0.3.0"; src = ./.; + format = "pyproject"; + + nativeBuildInputs = with pkgs.python311Packages; [ + hatchling + ]; + + propagatedBuildInputs = with pkgs.python311Packages; [ + jinja2 + pyyaml + gitpython + click + rich + jsonschema + ]; - nativeBuildInputs = [ pkgs.makeWrapper ]; - - buildPhase = '' - # Nothing to build, we just need to wrap the Python package - ''; - - installPhase = '' - mkdir -p $out/bin - - # Create wrapper for deepwork CLI - makeWrapper ${pythonWithDeepwork}/bin/deepwork $out/bin/deepwork \ - --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" - - # Create wrapper scripts for claude hook - makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-claude-hook \ - --add-flags "-m" \ - --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" \ - --set DEEPWORK_HOOK_PLATFORM "claude" - - # Create wrapper scripts for gemini hook - makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-gemini-hook \ - --add-flags "-m" \ - --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" \ - --set DEEPWORK_HOOK_PLATFORM "gemini" - - # Also create a python wrapper that has deepwork in PYTHONPATH - makeWrapper ${pythonWithDeepwork}/bin/python $out/bin/deepwork-python \ - --set PYTHONPATH "${pythonWithDeepwork}/${pythonWithDeepwork.sitePackages}" - ''; + # Skip tests during build (they can be run in devShell) + doCheck = false; meta = with pkgs.lib; { description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; homepage = "https://github.com/Unsupervisedcom/deepwork"; + # Business Source License 1.1 - not OSI approved license = { fullName = "Business Source License 1.1"; url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; diff --git a/src/deepwork/cli/hook.py b/src/deepwork/cli/hook.py new file mode 100644 index 00000000..d5abfcc3 --- /dev/null +++ b/src/deepwork/cli/hook.py @@ -0,0 +1,69 @@ +"""Hook command for DeepWork CLI. + +This command runs hook scripts, allowing hooks to use the `deepwork` CLI +instead of `python -m deepwork.hooks.*`, which works regardless of how +deepwork was installed (flake, pipx, uv, etc.). + +Usage: + deepwork hook rules_check + deepwork hook + +This is meant to be called from hook wrapper scripts (claude_hook.sh, gemini_hook.sh). +""" + +import sys +import importlib +from pathlib import Path + +import click +from rich.console import Console + +console = Console() + + +class HookError(Exception): + """Exception raised for hook errors.""" + + pass + + +@click.command() +@click.argument("hook_name") +def hook(hook_name: str) -> None: + """ + Run a DeepWork hook by name. + + HOOK_NAME: Name of the hook to run (e.g., 'rules_check') + + This command imports and runs the hook module from deepwork.hooks.{hook_name}. + The hook receives stdin input and outputs to stdout, following the hook protocol. + + Examples: + deepwork hook rules_check + echo '{}' | deepwork hook rules_check + """ + try: + # Import the hook module + module_name = f"deepwork.hooks.{hook_name}" + try: + module = importlib.import_module(module_name) + except ModuleNotFoundError: + raise HookError( + f"Hook '{hook_name}' not found. " + f"Available hooks are in the deepwork.hooks package." + ) + + # Run the hook's main function if it exists + if hasattr(module, "main"): + sys.exit(module.main()) + else: + raise HookError( + f"Hook module '{module_name}' does not have a main() function" + ) + + except HookError as e: + console.print(f"[red]Error:[/red] {e}", file=sys.stderr) + sys.exit(1) + except Exception as e: + console.print(f"[red]Unexpected error running hook:[/red] {e}", file=sys.stderr) + sys.exit(1) diff --git a/src/deepwork/cli/main.py b/src/deepwork/cli/main.py index 24a0b717..f1b72606 100644 --- a/src/deepwork/cli/main.py +++ b/src/deepwork/cli/main.py @@ -16,9 +16,11 @@ def cli() -> None: # Import commands from deepwork.cli.install import install # noqa: E402 from deepwork.cli.sync import sync # noqa: E402 +from deepwork.cli.hook import hook # noqa: E402 cli.add_command(install) cli.add_command(sync) +cli.add_command(hook) if __name__ == "__main__": diff --git a/src/deepwork/hooks/__init__.py b/src/deepwork/hooks/__init__.py index c64dcfc4..e886c7d4 100644 --- a/src/deepwork/hooks/__init__.py +++ b/src/deepwork/hooks/__init__.py @@ -17,7 +17,7 @@ "Stop": [{ "hooks": [{ "type": "command", - "command": ".deepwork/hooks/claude_hook.sh deepwork.hooks.rules_check" + "command": ".deepwork/hooks/claude_hook.sh rules_check" }] }] } @@ -29,12 +29,15 @@ "AfterAgent": [{ "hooks": [{ "type": "command", - "command": ".gemini/hooks/gemini_hook.sh deepwork.hooks.rules_check" + "command": ".gemini/hooks/gemini_hook.sh rules_check" }] }] } } +The shell wrappers call `deepwork hook ` which works regardless +of how deepwork was installed (pipx, uv, nix flake, etc.). + Writing custom hooks: from deepwork.hooks.wrapper import ( HookInput, @@ -49,11 +52,14 @@ def my_hook(input: HookInput) -> HookOutput: if should_block(): return HookOutput(decision="block", reason="Complete X first") return HookOutput() - - if __name__ == "__main__": + + def main(): import os, sys platform = Platform(os.environ.get("DEEPWORK_HOOK_PLATFORM", "claude")) sys.exit(run_hook(my_hook, platform)) + + if __name__ == "__main__": + main() """ from deepwork.hooks.wrapper import ( diff --git a/src/deepwork/hooks/claude_hook.sh b/src/deepwork/hooks/claude_hook.sh index 7e13ad44..c9a53e12 100755 --- a/src/deepwork/hooks/claude_hook.sh +++ b/src/deepwork/hooks/claude_hook.sh @@ -6,14 +6,13 @@ # and work on any supported platform. # # Usage: -# claude_hook.sh +# claude_hook.sh # # Example: -# claude_hook.sh deepwork.hooks.rules_check +# claude_hook.sh rules_check # -# The Python module should implement a main() function that: -# 1. Calls deepwork.hooks.wrapper.run_hook() with a hook function -# 2. The hook function receives HookInput and returns HookOutput +# The hook is run via the deepwork CLI, which works regardless of how +# deepwork was installed (pipx, uv, nix flake, etc.). # # Environment variables set by Claude Code: # CLAUDE_PROJECT_DIR - Absolute path to project root @@ -26,12 +25,12 @@ set -e -# Get the Python module to run -PYTHON_MODULE="${1:-}" +# Get the hook name to run +HOOK_NAME="${1:-}" -if [ -z "${PYTHON_MODULE}" ]; then - echo "Usage: claude_hook.sh " >&2 - echo "Example: claude_hook.sh deepwork.hooks.rules_check" >&2 +if [ -z "${HOOK_NAME}" ]; then + echo "Usage: claude_hook.sh " >&2 + echo "Example: claude_hook.sh rules_check" >&2 exit 1 fi @@ -41,15 +40,12 @@ if [ ! -t 0 ]; then HOOK_INPUT=$(cat) fi -# Set platform environment variable for the Python module +# Set platform environment variable for the hook export DEEPWORK_HOOK_PLATFORM="claude" -# Run the Python module, passing the input via stdin -# The Python module is responsible for: -# 1. Reading stdin (normalized by wrapper) -# 2. Processing the hook logic -# 3. Writing JSON to stdout -echo "${HOOK_INPUT}" | python -m "${PYTHON_MODULE}" +# Run the hook via deepwork CLI +# This works regardless of how deepwork was installed (pipx, uv, nix flake, etc.) +echo "${HOOK_INPUT}" | deepwork hook "${HOOK_NAME}" exit_code=$? exit ${exit_code} diff --git a/src/deepwork/hooks/gemini_hook.sh b/src/deepwork/hooks/gemini_hook.sh index a2bb09da..0daa551e 100755 --- a/src/deepwork/hooks/gemini_hook.sh +++ b/src/deepwork/hooks/gemini_hook.sh @@ -6,14 +6,13 @@ # and work on any supported platform. # # Usage: -# gemini_hook.sh +# gemini_hook.sh # # Example: -# gemini_hook.sh deepwork.hooks.rules_check +# gemini_hook.sh rules_check # -# The Python module should implement a main() function that: -# 1. Calls deepwork.hooks.wrapper.run_hook() with a hook function -# 2. The hook function receives HookInput and returns HookOutput +# The hook is run via the deepwork CLI, which works regardless of how +# deepwork was installed (pipx, uv, nix flake, etc.). # # Environment variables set by Gemini CLI: # GEMINI_PROJECT_DIR - Absolute path to project root @@ -26,12 +25,12 @@ set -e -# Get the Python module to run -PYTHON_MODULE="${1:-}" +# Get the hook name to run +HOOK_NAME="${1:-}" -if [ -z "${PYTHON_MODULE}" ]; then - echo "Usage: gemini_hook.sh " >&2 - echo "Example: gemini_hook.sh deepwork.hooks.rules_check" >&2 +if [ -z "${HOOK_NAME}" ]; then + echo "Usage: gemini_hook.sh " >&2 + echo "Example: gemini_hook.sh rules_check" >&2 exit 1 fi @@ -41,15 +40,12 @@ if [ ! -t 0 ]; then HOOK_INPUT=$(cat) fi -# Set platform environment variable for the Python module +# Set platform environment variable for the hook export DEEPWORK_HOOK_PLATFORM="gemini" -# Run the Python module, passing the input via stdin -# The Python module is responsible for: -# 1. Reading stdin (normalized by wrapper) -# 2. Processing the hook logic -# 3. Writing JSON to stdout -echo "${HOOK_INPUT}" | python -m "${PYTHON_MODULE}" +# Run the hook via deepwork CLI +# This works regardless of how deepwork was installed (pipx, uv, nix flake, etc.) +echo "${HOOK_INPUT}" | deepwork hook "${HOOK_NAME}" exit_code=$? exit ${exit_code} diff --git a/src/deepwork/hooks/rules_check.py b/src/deepwork/hooks/rules_check.py index 2e6694c7..235cd1cc 100644 --- a/src/deepwork/hooks/rules_check.py +++ b/src/deepwork/hooks/rules_check.py @@ -6,12 +6,15 @@ Rule files are loaded from .deepwork/rules/ directory as frontmatter markdown files. -Usage (via shell wrapper): - claude_hook.sh deepwork.hooks.rules_check - gemini_hook.sh deepwork.hooks.rules_check +Usage (via shell wrapper - recommended): + claude_hook.sh rules_check + gemini_hook.sh rules_check -Or directly with platform environment variable: - DEEPWORK_HOOK_PLATFORM=claude python -m deepwork.hooks.rules_check +Or directly via deepwork CLI: + deepwork hook rules_check + +Or with platform environment variable: + DEEPWORK_HOOK_PLATFORM=claude deepwork hook rules_check """ from __future__ import annotations From 54c97d24aa653ab6b3797adce264e5c9e3d8ffed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:06:46 +0000 Subject: [PATCH 16/28] Replace shell.nix with flake-compat wrapper Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- CONTRIBUTING.md | 8 +++-- doc/nix-flake.md | 10 ++++-- shell.nix | 88 ++++++++++++------------------------------------ 3 files changed, 34 insertions(+), 72 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b44e14b4..7b575756 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,17 +129,19 @@ cd deepwork nix develop ``` -#### Legacy Support (shell.nix) +#### Legacy Support (nix-shell) -For compatibility, `shell.nix` is still available: +For users who prefer the traditional `nix-shell` command, `shell.nix` is available as a compatibility wrapper. It uses `flake-compat` to provide the same environment as the flake: ```bash nix-shell ``` +**Note:** The `shell.nix` file imports the development shell from `flake.nix` via flake-compat, ensuring consistency between `nix-shell` and `nix develop`. + #### What's Included -When you enter the Nix environment (via flake or shell.nix), you'll see a welcome message with available tools. The environment includes: +When you enter the Nix environment (via `nix develop`, `nix-shell`, or direnv), you'll see a welcome message with available tools. The environment includes: - Python 3.11 - uv (package manager) - pytest, ruff, mypy diff --git a/doc/nix-flake.md b/doc/nix-flake.md index d7d46282..178ff3bf 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -389,13 +389,19 @@ nix develop ## Backward Compatibility -The `shell.nix` file is still maintained for users who prefer the traditional approach: +The `shell.nix` file is maintained as a compatibility wrapper for users who prefer the traditional `nix-shell` approach. It uses `flake-compat` to import the development shell from `flake.nix`, ensuring you get the same environment whether you use: ```bash +# Modern approach (recommended) +nix develop + +# Legacy approach (still works) nix-shell ``` -This provides the same environment as `nix develop`, just using the legacy interface. +Both commands provide the same development environment, with all dependencies and environment variables properly configured. The only difference is the command syntax. + +**Note:** New users should prefer `nix develop` or direnv integration (`direnv allow`) as these are the modern, actively maintained approaches. ## Additional Resources diff --git a/shell.nix b/shell.nix index 5965287c..8439e907 100644 --- a/shell.nix +++ b/shell.nix @@ -1,67 +1,21 @@ -{ pkgs ? import {} }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - # Python 3.11 or later - python311 - python311Packages.pip - python311Packages.virtualenv - - # Modern Python tooling - uv - - # Git for version control - git - - # Additional tools - jq # For JSON processing - - # Python development dependencies - python311Packages.jinja2 - python311Packages.pyyaml - python311Packages.gitpython - python311Packages.pytest - python311Packages.pytest-mock - python311Packages.pytest-cov - python311Packages.click - python311Packages.rich - - # Linting and type checking - ruff - mypy - ]; - - shellHook = '' - # Set up environment variables - export PYTHONPATH="$PWD/src:$PYTHONPATH" - export DEEPWORK_DEV=1 - - # Auto-sync dependencies and activate venv for direct deepwork access - echo "Setting up DeepWork development environment..." - uv sync --quiet 2>/dev/null || uv sync - - # Activate the virtual environment so 'deepwork' command is directly available - if [ -f .venv/bin/activate ]; then - source .venv/bin/activate - fi - - echo "" - echo "DeepWork Development Environment" - echo "================================" - echo "" - echo "Python version: $(python --version)" - echo "uv version: $(uv --version)" - echo "" - echo "Available tools:" - echo " - deepwork: CLI is ready (try 'deepwork --help')" - echo " - pytest: Testing framework" - echo " - ruff: Python linter and formatter" - echo " - mypy: Static type checker" - echo "" - echo "Quick start:" - echo " - 'deepwork --help' to see available commands" - echo " - 'pytest' to run tests" - echo " - Read doc/architecture.md for design details" - echo "" - ''; -} +# Legacy nix-shell compatibility wrapper +# This file provides backward compatibility for users still using `nix-shell`. +# It imports the devShell from flake.nix, ensuring the same environment +# regardless of whether you use `nix-shell` or `nix develop`. +# +# Modern users should use: +# nix develop (flakes) +# or with direnv: +# direnv allow (automatically uses the flake) +# +# Legacy users can still use: +# nix-shell (uses this compatibility wrapper) + +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/master.tar.gz"; + sha256 = "0pf91w4f6nnlxy3z1vdz5jq9b4qqls4s7xhd0pahph8smxka91w7"; + } +) { + src = ./.; +}).shellNix From 962792197853ba0b435a2eac6501460dcd52bf51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:56:01 +0000 Subject: [PATCH 17/28] Changes before error encountered Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- CONTRIBUTING.md | 16 +++------------- shell.nix | 21 --------------------- 2 files changed, 3 insertions(+), 34 deletions(-) delete mode 100644 shell.nix diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b575756..c47b66a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,19 +129,9 @@ cd deepwork nix develop ``` -#### Legacy Support (nix-shell) - -For users who prefer the traditional `nix-shell` command, `shell.nix` is available as a compatibility wrapper. It uses `flake-compat` to provide the same environment as the flake: - -```bash -nix-shell -``` - -**Note:** The `shell.nix` file imports the development shell from `flake.nix` via flake-compat, ensuring consistency between `nix-shell` and `nix develop`. - #### What's Included -When you enter the Nix environment (via `nix develop`, `nix-shell`, or direnv), you'll see a welcome message with available tools. The environment includes: +When you enter the Nix environment (via `nix develop` or direnv), you'll see a welcome message with available tools. The environment includes: - Python 3.11 - uv (package manager) - pytest, ruff, mypy @@ -183,7 +173,7 @@ To use your local development version of DeepWork, install it in **editable mode # Install in editable mode with development dependencies uv pip install -e ".[dev]" -# Or if you're inside nix-shell +# Inside the Nix development environment uv sync # Automatically installs in editable mode ``` @@ -271,7 +261,7 @@ uv run pytest # Or with explicit paths uv run pytest tests/ -v -# Using pytest directly (if in nix-shell or venv) +# Using pytest directly (in Nix environment or venv) pytest ``` diff --git a/shell.nix b/shell.nix deleted file mode 100644 index 8439e907..00000000 --- a/shell.nix +++ /dev/null @@ -1,21 +0,0 @@ -# Legacy nix-shell compatibility wrapper -# This file provides backward compatibility for users still using `nix-shell`. -# It imports the devShell from flake.nix, ensuring the same environment -# regardless of whether you use `nix-shell` or `nix develop`. -# -# Modern users should use: -# nix develop (flakes) -# or with direnv: -# direnv allow (automatically uses the flake) -# -# Legacy users can still use: -# nix-shell (uses this compatibility wrapper) - -(import ( - fetchTarball { - url = "https://github.com/edolstra/flake-compat/archive/master.tar.gz"; - sha256 = "0pf91w4f6nnlxy3z1vdz5jq9b4qqls4s7xhd0pahph8smxka91w7"; - } -) { - src = ./.; -}).shellNix From d9943489f63e32d26acbc47a28428ddaf1cf5832 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:05:26 +0000 Subject: [PATCH 18/28] Remove shell.nix and all references to nix-shell Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- CONTRIBUTING.md | 17 +++++++++-------- doc/nix-flake.md | 16 ---------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c47b66a8..e3df076e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -438,7 +438,7 @@ deepwork/ ├── doc/ # Documentation │ ├── architecture.md # Comprehensive architecture doc │ └── TEMPLATE_REVIEW.md -├── shell.nix # Nix development environment +├── flake.nix # Nix flake for development environment ├── pyproject.toml # Python project configuration ├── CLAUDE.md # Project context for Claude Code └── README.md # Project overview @@ -516,10 +516,10 @@ deepwork/ ### Quick Development Cycle ```bash -# In one terminal: Enter nix-shell and keep it open -nix-shell +# In one terminal: Enter Nix development environment +nix develop -# In nix-shell: Watch tests +# In Nix environment: Watch tests uv run pytest tests/unit/ --watch # In another terminal: Make changes to src/deepwork/ @@ -571,11 +571,12 @@ pip list | grep deepwork # Should show: deepwork 0.1.0 /path/to/your/local/deepwork/src ``` -### Issue: Nix shell not loading -**Solution**: Make sure Nix is installed and `` is available: +### Issue: Nix environment not loading +**Solution**: Make sure Nix is installed with flakes enabled: ```bash -nix-shell --version -echo $NIX_PATH +nix --version +# Add to ~/.config/nix/nix.conf if not already there: +# experimental-features = nix-command flakes ``` ## License diff --git a/doc/nix-flake.md b/doc/nix-flake.md index 178ff3bf..b650d599 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -387,22 +387,6 @@ Or ensure you're in the Nix environment: nix develop ``` -## Backward Compatibility - -The `shell.nix` file is maintained as a compatibility wrapper for users who prefer the traditional `nix-shell` approach. It uses `flake-compat` to import the development shell from `flake.nix`, ensuring you get the same environment whether you use: - -```bash -# Modern approach (recommended) -nix develop - -# Legacy approach (still works) -nix-shell -``` - -Both commands provide the same development environment, with all dependencies and environment variables properly configured. The only difference is the command syntax. - -**Note:** New users should prefer `nix develop` or direnv integration (`direnv allow`) as these are the modern, actively maintained approaches. - ## Additional Resources - [Nix Flakes Documentation](https://nixos.wiki/wiki/Flakes) From 1c9b0ef7fdf3a67be8a2ef1fa415073632e5014c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:06:01 +0000 Subject: [PATCH 19/28] Remove final nix-shell reference from README Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 1df8263b..68a3aecd 100644 --- a/README.md +++ b/README.md @@ -211,12 +211,9 @@ DeepWork is available as a Nix flake for reproducible development environments: # Using Nix flakes nix develop -# Or with direnv (automatic activation) +# Or with direnv (automatic activation - recommended) echo "use flake" > .envrc direnv allow - -# Legacy Nix shell -nix-shell ``` The Nix environment provides all dependencies including Python 3.11, uv, pytest, ruff, and mypy. From cc083dcb5e65df2ac3f518c2a644e7c9d3965cd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:43:09 +0000 Subject: [PATCH 20/28] Add rpds-py dependency to fix ModuleNotFoundError Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 6ab17be6..0f70abe7 100644 --- a/flake.nix +++ b/flake.nix @@ -31,6 +31,7 @@ click rich jsonschema + rpds-py # Required by jsonschema's referencing dependency ]; # Skip tests during build (they can be run in devShell) From b695b4e7a48dd651c97df01236a2cdb80cbe6c02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:00:45 +0000 Subject: [PATCH 21/28] Document custom hooks and Python invocation with Nix flake Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- doc/nix-flake.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/doc/nix-flake.md b/doc/nix-flake.md index b650d599..1157b483 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -351,6 +351,61 @@ python -m deepwork.hooks.rules_check # ❌ Doesn't work with all install method All these methods ensure `deepwork` is available globally, so hooks work correctly outside of development environments. +### Custom Hooks and Direct Python Invocation + +**Standard Hooks:** +Standard hooks (like `rules_check`) work seamlessly with all installation methods because they use the `deepwork hook` CLI command: + +```bash +# This works with Nix flake, pipx, uv, and pip installations +deepwork hook rules_check +``` + +**Custom Hooks:** +If you have custom hooks that need to invoke Python directly (e.g., `python -m deepwork.hooks.custom_hook` or `python myscript.py`), there are important considerations: + +**Nix Flake Installation:** +When deepwork is installed via `nix profile install`, only the `deepwork` command is exposed, not a Python interpreter with deepwork in its module path. This means: + +- ✅ **Works:** `deepwork hook custom_hook` (if you've registered your custom hook via the CLI) +- ❌ **Doesn't Work:** `python -m deepwork.hooks.custom_hook` (Python won't find the deepwork module) +- ❌ **Doesn't Work:** `python /path/to/custom_script.py` (if it imports deepwork) + +**Recommended Approach for Custom Hooks:** + +1. **Use the `deepwork hook` command** (Recommended): + Register your custom hook so it can be invoked via `deepwork hook`: + ```bash + # Your hook wrapper calls this + deepwork hook my_custom_hook + ``` + + This approach works consistently across all installation methods. + +2. **Use pipx or uv for custom hooks** (Alternative): + If you need direct Python access to deepwork modules: + ```bash + # Install with pipx (recommended for global tools) + pipx install deepwork + + # Now python can find deepwork + python -m deepwork.hooks.custom_hook + ``` + +3. **Development Environment Only** (Local Development): + For development and testing: + ```bash + # Use nix develop for full Python environment + nix develop + # Now python has access to deepwork modules + python -m deepwork.hooks.custom_hook + ``` + +**Summary:** +- **Standard hooks:** Work with all installation methods via `deepwork hook` +- **Custom hooks needing Python:** Use `deepwork hook` command or install via pipx/uv instead of Nix flake +- **Development/Testing:** Use `nix develop` for full Python environment access + ### direnv Not Working 1. Make sure direnv is installed: From 3bb8ac221506530d7988fe5953f6b2c9be9849aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 16:37:46 +0000 Subject: [PATCH 22/28] Fix Python formatting with ruff Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- src/deepwork/cli/hook.py | 17 +++++++---------- src/deepwork/hooks/__init__.py | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/deepwork/cli/hook.py b/src/deepwork/cli/hook.py index d5abfcc3..3d590c25 100644 --- a/src/deepwork/cli/hook.py +++ b/src/deepwork/cli/hook.py @@ -32,12 +32,12 @@ class HookError(Exception): def hook(hook_name: str) -> None: """ Run a DeepWork hook by name. - + HOOK_NAME: Name of the hook to run (e.g., 'rules_check') - + This command imports and runs the hook module from deepwork.hooks.{hook_name}. The hook receives stdin input and outputs to stdout, following the hook protocol. - + Examples: deepwork hook rules_check echo '{}' | deepwork hook rules_check @@ -49,18 +49,15 @@ def hook(hook_name: str) -> None: module = importlib.import_module(module_name) except ModuleNotFoundError: raise HookError( - f"Hook '{hook_name}' not found. " - f"Available hooks are in the deepwork.hooks package." + f"Hook '{hook_name}' not found. Available hooks are in the deepwork.hooks package." ) - + # Run the hook's main function if it exists if hasattr(module, "main"): sys.exit(module.main()) else: - raise HookError( - f"Hook module '{module_name}' does not have a main() function" - ) - + raise HookError(f"Hook module '{module_name}' does not have a main() function") + except HookError as e: console.print(f"[red]Error:[/red] {e}", file=sys.stderr) sys.exit(1) diff --git a/src/deepwork/hooks/__init__.py b/src/deepwork/hooks/__init__.py index e886c7d4..5e9d8d43 100644 --- a/src/deepwork/hooks/__init__.py +++ b/src/deepwork/hooks/__init__.py @@ -52,7 +52,7 @@ def my_hook(input: HookInput) -> HookOutput: if should_block(): return HookOutput(decision="block", reason="Complete X first") return HookOutput() - + def main(): import os, sys platform = Platform(os.environ.get("DEEPWORK_HOOK_PLATFORM", "claude")) From f02523938317c9594861a222cbd5badf5aef26d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:31:05 +0000 Subject: [PATCH 23/28] Fix ruff linting issues: organize imports and fix exception handling Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- src/deepwork/cli/hook.py | 5 ++--- src/deepwork/cli/main.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/deepwork/cli/hook.py b/src/deepwork/cli/hook.py index 3d590c25..0607da11 100644 --- a/src/deepwork/cli/hook.py +++ b/src/deepwork/cli/hook.py @@ -11,9 +11,8 @@ This is meant to be called from hook wrapper scripts (claude_hook.sh, gemini_hook.sh). """ -import sys import importlib -from pathlib import Path +import sys import click from rich.console import Console @@ -50,7 +49,7 @@ def hook(hook_name: str) -> None: except ModuleNotFoundError: raise HookError( f"Hook '{hook_name}' not found. Available hooks are in the deepwork.hooks package." - ) + ) from None # Run the hook's main function if it exists if hasattr(module, "main"): diff --git a/src/deepwork/cli/main.py b/src/deepwork/cli/main.py index f1b72606..840decbf 100644 --- a/src/deepwork/cli/main.py +++ b/src/deepwork/cli/main.py @@ -14,9 +14,9 @@ def cli() -> None: # Import commands +from deepwork.cli.hook import hook # noqa: E402 from deepwork.cli.install import install # noqa: E402 from deepwork.cli.sync import sync # noqa: E402 -from deepwork.cli.hook import hook # noqa: E402 cli.add_command(install) cli.add_command(sync) From a2517a13046633a58732da27dfea2da5e9539428 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:30:48 +0000 Subject: [PATCH 24/28] Fix hook CLI to support custom module paths and remove invalid console.print parameter Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- src/deepwork/cli/hook.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/deepwork/cli/hook.py b/src/deepwork/cli/hook.py index 0607da11..e0687dba 100644 --- a/src/deepwork/cli/hook.py +++ b/src/deepwork/cli/hook.py @@ -43,7 +43,13 @@ def hook(hook_name: str) -> None: """ try: # Import the hook module - module_name = f"deepwork.hooks.{hook_name}" + # If the hook_name contains a dot, treat it as a full module path + # Otherwise, assume it's a hook in the deepwork.hooks package + if "." in hook_name: + module_name = hook_name + else: + module_name = f"deepwork.hooks.{hook_name}" + try: module = importlib.import_module(module_name) except ModuleNotFoundError: @@ -58,8 +64,8 @@ def hook(hook_name: str) -> None: raise HookError(f"Hook module '{module_name}' does not have a main() function") except HookError as e: - console.print(f"[red]Error:[/red] {e}", file=sys.stderr) + console.print(f"[red]Error:[/red] {e}", style="bold red") sys.exit(1) except Exception as e: - console.print(f"[red]Unexpected error running hook:[/red] {e}", file=sys.stderr) + console.print(f"[red]Unexpected error running hook:[/red] {e}", style="bold red") sys.exit(1) From 135e00d06168844262d66262782020971ffea473 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:46:25 +0000 Subject: [PATCH 25/28] Remove trailing whitespace in hook.py Co-authored-by: ncrmro <8276365+ncrmro@users.noreply.github.com> --- src/deepwork/cli/hook.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/deepwork/cli/hook.py b/src/deepwork/cli/hook.py index e0687dba..5182b20a 100644 --- a/src/deepwork/cli/hook.py +++ b/src/deepwork/cli/hook.py @@ -49,7 +49,6 @@ def hook(hook_name: str) -> None: module_name = hook_name else: module_name = f"deepwork.hooks.{hook_name}" - try: module = importlib.import_module(module_name) except ModuleNotFoundError: From 203ba9fd11ad7bd1cbf6ebd2e2b773e733a46c05 Mon Sep 17 00:00:00 2001 From: Nicholas Romero Date: Wed, 21 Jan 2026 16:08:17 -0600 Subject: [PATCH 26/28] docs: explain auto-unfree license config in nix-flake.md --- CONTRIBUTING.md | 150 +++++++++++++++++++++++++++++------------------ doc/nix-flake.md | 8 +++ flake.nix | 127 ++++++++++++++++----------------------- result | 1 + uv.lock | 2 +- 5 files changed, 153 insertions(+), 135 deletions(-) create mode 120000 result diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e3df076e..85e8994d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -98,9 +98,9 @@ Once direnv is set up, the environment will activate automatically when you ente The easiest way to get started is using Nix flakes, which provides a fully reproducible development environment with all dependencies pre-configured. -#### Quick Start with direnv (Automatic) +#### Quick Start with direnv (Recommended) -If you have direnv installed, the environment will activate automatically: +If you have direnv installed, the entire development environment activates automatically when you `cd` into the project: ```bash # Clone the repository @@ -110,11 +110,20 @@ cd deepwork # Allow direnv (first time only) direnv allow -# Environment activates automatically! -# You'll see the DeepWork welcome message +# That's it! Everything is ready: +deepwork --help # CLI works +pytest # Tests work +ruff check src/ # Linting works ``` -The `.envrc` file configures direnv to use the Nix flake, so you'll automatically enter the development environment whenever you `cd` into the directory. +The `.envrc` file contains `use flake`, which tells direnv to load the Nix flake's development shell. This automatically: + +1. Creates `.venv/` if it doesn't exist +2. Installs all dependencies via `uv sync --all-extras` +3. Adds `.venv/bin` to your PATH +4. Sets `PYTHONPATH` and `DEEPWORK_DEV=1` + +Every time you `cd` into the directory, the environment is ready instantly (venv is reused, deps are cached). #### Manual Flake Usage @@ -131,13 +140,26 @@ nix develop #### What's Included -When you enter the Nix environment (via `nix develop` or direnv), you'll see a welcome message with available tools. The environment includes: -- Python 3.11 -- uv (package manager) -- pytest, ruff, mypy -- All Python dependencies -- Environment variables (`PYTHONPATH`, `DEEPWORK_DEV=1`) -- Automatic virtual environment activation +The Nix environment provides: + +| Tool | Description | +|------|-------------| +| `deepwork` | CLI using your local source code (editable install) | +| `pytest` | Test runner with all plugins | +| `ruff` | Fast Python linter and formatter | +| `mypy` | Static type checker | +| `uv` | Python package manager | +| `python` | Python 3.11 interpreter | + +#### CI Usage + +For CI pipelines or scripts, use `nix develop --command`: + +```bash +nix develop --command pytest +nix develop --command ruff check src/ +nix develop --command mypy src/ +``` ### Option 2: Manual Setup (Without Nix) @@ -148,39 +170,38 @@ If you prefer not to use Nix: git clone https://github.com/deepwork/deepwork.git cd deepwork -# Create a virtual environment (optional but recommended) -python3.11 -m venv venv -source venv/bin/activate # On Windows: venv\Scripts\activate - -# Install uv if you don't have it -pip install uv +# Install uv if you don't have it (see https://docs.astral.sh/uv/getting-started/installation/) +curl -LsSf https://astral.sh/uv/install.sh | sh -# Install dependencies -uv sync +# Create virtual environment and install all dependencies (including dev tools) +uv venv .venv +source .venv/bin/activate # On Windows: .venv\Scripts\activate +uv sync --all-extras -# Set PYTHONPATH for development +# Set environment variables for development export PYTHONPATH="$PWD/src:$PYTHONPATH" export DEEPWORK_DEV=1 ``` ## Installing DeepWork Locally -To use your local development version of DeepWork, install it in **editable mode**. This allows you to make changes to the code and have them immediately reflected without reinstalling. +The development version of DeepWork is installed automatically in **editable mode**, meaning changes to source code are reflected immediately without reinstalling. -### Using uv (Recommended) +### With Nix (Automatic) -```bash -# Install in editable mode with development dependencies -uv pip install -e ".[dev]" +If you're using the Nix development environment, DeepWork is already installed in editable mode. No additional steps needed. -# Inside the Nix development environment -uv sync # Automatically installs in editable mode -``` +### Without Nix (Manual) + +If you set up manually, the `uv sync --all-extras` command installs DeepWork in editable mode automatically. -### Using pip +Alternatively, you can install explicitly: ```bash -# Install in editable mode with development dependencies +# Using uv +uv pip install -e ".[dev]" + +# Or using pip pip install -e ".[dev]" ``` @@ -190,11 +211,11 @@ pip install -e ".[dev]" # Check that the deepwork command is available deepwork --help -# Verify you're using the local version -which deepwork # Should point to your local environment +# Verify you're using the local development version +which deepwork # Should point to .venv/bin/deepwork -# Check version (should show 0.1.0 or current dev version) -python -c "import deepwork; print(deepwork.__version__)" +# Check version +deepwork --version ``` ## Testing Your Local Installation @@ -250,35 +271,35 @@ claude # Start Claude Code ## Running Tests -DeepWork has a comprehensive test suite with unit and integration tests. +DeepWork has a comprehensive test suite with 568+ tests. ### Run All Tests ```bash -# Using uv (recommended) -uv run pytest +# In Nix environment (interactive or CI) +pytest -# Or with explicit paths -uv run pytest tests/ -v +# Or using nix develop --command (CI-friendly, no interactive shell) +nix develop --command pytest -# Using pytest directly (in Nix environment or venv) -pytest +# Using uv run (without Nix) +uv run pytest ``` ### Run Specific Test Types ```bash -# Unit tests only (147 tests) -uv run pytest tests/unit/ -v +# Unit tests only +pytest tests/unit/ -v -# Integration tests only (19 tests) -uv run pytest tests/integration/ -v +# Integration tests only +pytest tests/integration/ -v # Run a specific test file -uv run pytest tests/unit/core/test_parser.py -v +pytest tests/unit/core/test_parser.py -v # Run a specific test function -uv run pytest tests/unit/core/test_parser.py::test_parse_valid_job -v +pytest tests/unit/core/test_parser.py::test_parse_valid_job -v ``` ### Test with Coverage @@ -553,32 +574,47 @@ uv run pytest --profile ## Common Issues ### Issue: `deepwork` command not found -**Solution**: Make sure you've installed in editable mode: +**With Nix**: Re-enter the development environment: ```bash -uv pip install -e . +nix develop +# or if using direnv +direnv reload +``` + +**Without Nix**: Ensure venv is activated and dependencies synced: +```bash +source .venv/bin/activate +uv sync --all-extras ``` ### Issue: Tests failing with import errors -**Solution**: Set PYTHONPATH: +**Solution**: This usually means dependencies aren't installed. Re-sync: ```bash -export PYTHONPATH="$PWD/src:$PYTHONPATH" +uv sync --all-extras ``` -### Issue: Changes not reflected in test project -**Solution**: Verify editable install: +### Issue: Changes not reflected +**Solution**: Verify editable install with uv: ```bash -pip list | grep deepwork -# Should show: deepwork 0.1.0 /path/to/your/local/deepwork/src +uv pip list | grep deepwork +# Should show: deepwork (editable) with path to your local directory ``` ### Issue: Nix environment not loading -**Solution**: Make sure Nix is installed with flakes enabled: +**Solution**: Ensure Nix is installed with flakes enabled: ```bash nix --version # Add to ~/.config/nix/nix.conf if not already there: # experimental-features = nix-command flakes ``` +### Issue: Old venv causing conflicts +**Solution**: Remove and let Nix recreate it: +```bash +rm -rf .venv +nix develop # Will recreate .venv automatically +``` + ## License By contributing to DeepWork, you agree that your contributions will be licensed under the project's current license. The licensor (Unsupervised.com, Inc.) reserves the right to change the project license at any time at its sole discretion. diff --git a/doc/nix-flake.md b/doc/nix-flake.md index 1157b483..315dfd0e 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -10,6 +10,14 @@ DeepWork provides a Nix flake for reproducible development environments and easy experimental-features = nix-command flakes ``` +## License Configuration + +DeepWork is licensed under the Business Source License 1.1 (BSL 1.1), which is not an OSI-approved open source license (though the source is available). + +The flake is configured to automatically allow unfree packages when importing `nixpkgs`, so you don't need to manually set `NIXPKGS_ALLOW_UNFREE=1` when building or using this flake directly. + +However, if you consume this flake in your own project, you may still need to configure your `nixpkgs` to allow unfree packages or specifically allow `deepwork` if your configuration overrides our default settings. + ## Development Environment ### Quick Start with direnv (Recommended) diff --git a/flake.nix b/flake.nix index 0f70abe7..4c457ba6 100644 --- a/flake.nix +++ b/flake.nix @@ -14,109 +14,82 @@ # Allow unfree packages to support the Business Source License 1.1 config.allowUnfree = true; }; + # Read version from pyproject.toml to avoid duplication + pyproject = builtins.fromTOML (builtins.readFile ./pyproject.toml); deepwork = pkgs.python311Packages.buildPythonPackage { pname = "deepwork"; - version = "0.3.0"; + version = pyproject.project.version; src = ./.; format = "pyproject"; - - nativeBuildInputs = with pkgs.python311Packages; [ - hatchling - ]; - + nativeBuildInputs = [ pkgs.python311Packages.hatchling ]; + # Required for `nix build` - must match pyproject.toml dependencies propagatedBuildInputs = with pkgs.python311Packages; [ - jinja2 - pyyaml - gitpython - click - rich - jsonschema - rpds-py # Required by jsonschema's referencing dependency + click gitpython jinja2 jsonschema pyyaml rich rpds-py ]; - - # Skip tests during build (they can be run in devShell) doCheck = false; - - meta = with pkgs.lib; { - description = "Framework for enabling AI agents to perform complex, multi-step work tasks"; - homepage = "https://github.com/Unsupervisedcom/deepwork"; - # Business Source License 1.1 - not OSI approved - license = { - fullName = "Business Source License 1.1"; - url = "https://github.com/Unsupervisedcom/deepwork/blob/main/LICENSE.md"; - free = false; - }; - }; }; in { devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ - # Python 3.11 or later + # Python 3.11 - base interpreter for uv python311 - python311Packages.pip - python311Packages.virtualenv - # Modern Python tooling + # uv manages all Python packages (deps, dev tools, etc.) uv # Git for version control git - # Additional tools + # System tools jq # For JSON processing - - # Python development dependencies - python311Packages.jinja2 - python311Packages.pyyaml - python311Packages.gitpython - python311Packages.pytest - python311Packages.pytest-mock - python311Packages.pytest-cov - python311Packages.click - python311Packages.rich - python311Packages.jsonschema - - # Linting and type checking - ruff - mypy ]; - shellHook = '' - # Set up environment variables - export PYTHONPATH="$PWD/src:$PYTHONPATH" - export DEEPWORK_DEV=1 + # Environment variables for uv integration with Nix + env = { + # Tell uv to use the Nix-provided Python interpreter + UV_PYTHON = "${pkgs.python311}/bin/python"; + # Prevent uv from downloading Python binaries + UV_PYTHON_DOWNLOADS = "never"; + # Development mode flag + DEEPWORK_DEV = "1"; + }; - # Auto-sync dependencies and activate venv for direct deepwork access - echo "Setting up DeepWork development environment..." - if ! uv sync --quiet 2>/dev/null; then - echo "Running uv sync..." - uv sync + shellHook = '' + # Create venv if it doesn't exist + if [ ! -d .venv ]; then + echo "Creating virtual environment..." + uv venv .venv --quiet fi - # Activate the virtual environment so 'deepwork' command is directly available - if [ -f .venv/bin/activate ]; then - source .venv/bin/activate - fi + # Sync dependencies (including dev extras like pytest, ruff, mypy) + # Run quietly - uv only outputs when changes are needed + uv sync --all-extras --quiet 2>/dev/null || uv sync --all-extras + + # Activate venv by setting environment variables directly + # This works reliably for both interactive shells and `nix develop --command` + export VIRTUAL_ENV="$PWD/.venv" + export PATH="$VIRTUAL_ENV/bin:$PATH" + unset PYTHONHOME - echo "" - echo "DeepWork Development Environment" - echo "================================" - echo "" - echo "Python version: $(python --version)" - echo "uv version: $(uv --version)" - echo "" - echo "Available tools:" - echo " - deepwork: CLI is ready (try 'deepwork --help')" - echo " - pytest: Testing framework" - echo " - ruff: Python linter and formatter" - echo " - mypy: Static type checker" - echo "" - echo "Quick start:" - echo " - 'deepwork --help' to see available commands" - echo " - 'pytest' to run tests" - echo " - Read doc/architecture.md for design details" - echo "" + # Set PYTHONPATH for editable install access to src/ + export PYTHONPATH="$PWD/src:$PYTHONPATH" + + # Only show welcome message in interactive shells + if [[ $- == *i* ]]; then + echo "" + echo "DeepWork Development Environment" + echo "================================" + echo "" + echo "Python: $(python --version) | uv: $(uv --version)" + echo "" + echo "Commands:" + echo " deepwork --help CLI (development version)" + echo " pytest Run tests" + echo " ruff check src/ Lint code" + echo " mypy src/ Type check" + echo "" + fi ''; }; diff --git a/result b/result new file mode 120000 index 00000000..9fb3912b --- /dev/null +++ b/result @@ -0,0 +1 @@ +/nix/store/hmxjpzgimzyf6gs76blmgxjims86cpq7-python3.11-deepwork-0.5.0 \ No newline at end of file diff --git a/uv.lock b/uv.lock index c4091ca4..564a99f6 100644 --- a/uv.lock +++ b/uv.lock @@ -126,7 +126,7 @@ toml = [ [[package]] name = "deepwork" -version = "0.3.0" +version = "0.5.0" source = { editable = "." } dependencies = [ { name = "click" }, From 1569be0a930758b6903c1187f2314f52d10b1f85 Mon Sep 17 00:00:00 2001 From: Nicholas Romero Date: Wed, 21 Jan 2026 16:10:21 -0600 Subject: [PATCH 27/28] docs: add dev env info to AGENTS.md --- AGENTS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 5f327754..3e469ef8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,4 +83,22 @@ deepwork/ ├── deepwork_jobs/ # ← Installed copy, NOT source of truth ├── deepwork_rules/ # ← Installed copy, NOT source of truth └── [bespoke_job]/ # ← Source of truth for bespoke only + +## Development Environment + +This project uses **Nix Flakes** to provide a reproducible development environment. + +### Using the Environment + +- **With direnv (Recommended)**: Just `cd` into the directory. The `.envrc` will automatically load the flake environment. +- **Without direnv**: Run `nix develop` to enter the shell. +- **Building**: Run `nix build` to build the package. + +**Note**: The flake is configured to automatically allow unfree packages (required for the BSL 1.1 license), so you do not need to set `NIXPKGS_ALLOW_UNFREE=1`. + +The environment includes: +- Python 3.11 +- uv (package manager) +- All dev dependencies (pytest, ruff, mypy, etc.) + ``` From b41dbc2bfd8644443d522b86e2a660ddd700e8e8 Mon Sep 17 00:00:00 2001 From: Nicholas Romero Date: Wed, 21 Jan 2026 16:12:02 -0600 Subject: [PATCH 28/28] docs: update nix-flake.md with recommended project configuration example --- doc/nix-flake.md | 71 +++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/doc/nix-flake.md b/doc/nix-flake.md index 315dfd0e..26bf82ec 100644 --- a/doc/nix-flake.md +++ b/doc/nix-flake.md @@ -217,41 +217,62 @@ For projects that need to support multiple systems (Linux, macOS, etc.): } ``` -### Complete Example with direnv +### Recommended Project Configuration -Create a complete development environment with DeepWork and direnv: +For a complete development environment with DeepWork and your preferred AI assistants, use this `flake.nix` structure. Note that `config.allowUnfree = true` is required to use DeepWork (BSL 1.1) and Claude Code. **flake.nix:** ```nix { - description = "My project using DeepWork"; + description = "AI-powered development environment"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - # Reference DeepWork from GitHub - deepwork.url = "github:Unsupervisedcom/deepwork"; + flake-utils.url = "github:numtide/flake-utils"; + deepwork = { + url = "github:Unsupervisedcom/deepwork"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, deepwork }: - let - system = "x86_64-linux"; - pkgs = import nixpkgs { inherit system; }; - in { - devShells.${system}.default = pkgs.mkShell { - buildInputs = [ - # Include DeepWork in the development environment - deepwork.packages.${system}.default - # Add other dependencies - pkgs.python311 - pkgs.git - ]; + outputs = { self, nixpkgs, flake-utils, deepwork }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + # Required for DeepWork and Claude Code + config.allowUnfree = true; + }; + in + { + devShells.default = pkgs.mkShell { + buildInputs = [ + # DeepWork CLI + deepwork.packages.${system}.default + + # AI Agents + pkgs.claude-code + pkgs.gemini-cli + + # Additional tools + pkgs.python3 + pkgs.nodejs + pkgs.git + ]; - shellHook = '' - echo "DeepWork is available!" - deepwork --version - ''; - }; - }; + shellHook = '' + echo "------------------------------------------------------------------" + echo "DeepWork Development Shell" + echo "------------------------------------------------------------------" + echo "Tools: deepwork, claude, gemini-cli" + echo "------------------------------------------------------------------" + + # Verify installation + deepwork --version + ''; + }; + } + ); } ``` @@ -263,7 +284,7 @@ use flake Then run: ```bash direnv allow -# Environment with DeepWork loads automatically +# Environment with DeepWork and AI agents loads automatically ``` ## Flake Outputs