@@ -27,9 +27,9 @@ Configuration files, build tooling, environment setup - this is the bureaucracy
**The value of your application lives in your source code, not configuration.**
-## What Stack Does
+## What Stackpanel Does
-Stack provides a complete development infrastructure toolkit:
+Stackpanel provides a complete development infrastructure toolkit:
- **Zero-config dev environments** - Automatic setup for popular stacks with deterministic ports
- **Secrets management** - Team-based encrypted secrets with AGE/SOPS
@@ -40,7 +40,7 @@ Stack provides a complete development infrastructure toolkit:
**No lock-in.** Generated files are standard formats in standard locations. Eject anytime with a normal codebase.
-**No Nix knowledge required.** If you can write JSON, you can configure Stack. Or just use the web UI.
+**No Nix knowledge required.** If you can write JSON, you can configure Stackpanel. Or just use the web UI.
## Quick Start
@@ -53,7 +53,7 @@ Stack provides a complete development infrastructure toolkit:
```bash
# Create a new project with the default template
-nix flake init -t github:darkmatter/stack
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel
# Set up direnv
echo 'use flake . --impure' > .envrc
@@ -72,24 +72,24 @@ nix develop --impure
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
devenv.url = "github:cachix/devenv";
- stack.url = "github:darkmatter/stack";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
imports = [
inputs.devenv.flakeModule
- inputs.stack.flakeModules.default
+ inputs.stackpanel.flakeModules.default
];
systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"];
perSystem = {pkgs, ...}: {
devenv.shells.default = {
- imports = [inputs.stack.devenvModules.default];
-
+ imports = [inputs.stackpanel.devenvModules.default];
+
# Your config
- stack.enable = true;
+ stackpanel.enable = true;
packages = [pkgs.nodejs pkgs.bun];
};
};
@@ -99,24 +99,24 @@ nix develop --impure
## Configuration
-Edit `.stack/config.nix` to configure your environment:
+Edit `.stackpanel/config.nix` to configure your environment:
```nix
{
enable = true;
-
+
# Themed shell prompt
theme.enable = true;
-
+
# VS Code integration
ide.vscode.enable = true;
-
+
# Global services
globalServices = {
postgres.enable = true;
redis.enable = true;
};
-
+
# AWS certificate auth
# aws.roles-anywhere.enable = true;
}
@@ -141,9 +141,9 @@ my-project → base port 4200
Team-based secrets with AGE encryption:
```nix
-stack.secrets = {
+stackpanel.secrets = {
master-key.enable = true;
-
+
apps.api = {
dev = {
DATABASE_URL = "postgres://...";
@@ -157,7 +157,7 @@ stack.secrets = {
Auto-generated VS Code workspace with:
- Correct terminal environment
-- Extension recommendations
+- Extension recommendations
- Debugger configurations
- Task runners
@@ -171,13 +171,13 @@ Local web UI at `localhost:9876` for:
## Documentation
-Full documentation is available at [stack.dev](https://stack.dev/docs):
+Full documentation is available at [stackpanel.dev](https://stackpanel.dev/docs):
-- [Quick Start Guide](https://stack.dev/docs/quick-start)
-- [Concepts](https://stack.dev/docs/concepts)
-- [Configuration Reference](https://stack.dev/docs/reference)
-- [Secrets Management](https://stack.dev/docs/features/secrets)
-- [AWS Integration](https://stack.dev/docs/features/aws)
+- [Quick Start Guide](https://stackpanel.dev/docs/quick-start)
+- [Concepts](https://stackpanel.dev/docs/concepts)
+- [Configuration Reference](https://stackpanel.dev/docs/reference)
+- [Secrets Management](https://stackpanel.dev/docs/features/secrets)
+- [AWS Integration](https://stackpanel.dev/docs/features/aws)
## Architecture
diff --git a/README.tmpl.md b/README.tmpl.md
index 845129ec..220bb12b 100644
--- a/README.tmpl.md
+++ b/README.tmpl.md
@@ -1,17 +1,17 @@
-
-
-
+
+
+
Ship products, not plumbing.
-
-
-
+
+
+
@@ -27,9 +27,9 @@ Configuration files, build tooling, environment setup - this is the bureaucracy
**The value of your application lives in your source code, not configuration.**
-## What Stack Does
+## What Stackpanel Does
-Stack provides a complete development infrastructure toolkit:
+Stackpanel provides a complete development infrastructure toolkit:
- **Zero-config dev environments** - Automatic setup for popular stacks with deterministic ports
- **Secrets management** - Team-based encrypted secrets with AGE/SOPS
@@ -40,7 +40,7 @@ Stack provides a complete development infrastructure toolkit:
**No lock-in.** Generated files are standard formats in standard locations. Eject anytime with a normal codebase.
-**No Nix knowledge required.** If you can write JSON, you can configure Stack. Or just use the web UI.
+**No Nix knowledge required.** If you can write JSON, you can configure Stackpanel. Or just use the web UI.
## Quick Start
@@ -53,7 +53,7 @@ Stack provides a complete development infrastructure toolkit:
```bash
# Create a new project with the default template
-nix flake init -t github:darkmatter/stack
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel
# Set up direnv
echo 'use flake . --impure' > .envrc
@@ -72,24 +72,24 @@ nix develop --impure
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
devenv.url = "github:cachix/devenv";
- stack.url = "github:darkmatter/stack";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
imports = [
inputs.devenv.flakeModule
- inputs.stack.flakeModules.default
+ inputs.stackpanel.flakeModules.default
];
systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"];
perSystem = {pkgs, ...}: {
devenv.shells.default = {
- imports = [inputs.stack.devenvModules.default];
-
+ imports = [inputs.stackpanel.devenvModules.default];
+
# Your config
- stack.enable = true;
+ stackpanel.enable = true;
packages = [pkgs.nodejs pkgs.bun];
};
};
@@ -99,24 +99,24 @@ nix develop --impure
## Configuration
-Edit `.stack/config.nix` to configure your environment:
+Edit `.stackpanel/config.nix` to configure your environment:
```nix
{
enable = true;
-
+
# Themed shell prompt
theme.enable = true;
-
+
# VS Code integration
ide.vscode.enable = true;
-
+
# Global services
globalServices = {
postgres.enable = true;
redis.enable = true;
};
-
+
# AWS certificate auth
# aws.roles-anywhere.enable = true;
}
@@ -124,13 +124,13 @@ Edit `.stack/config.nix` to configure your environment:
## Documentation
-Full documentation is available at [stack.dev](https://stack.dev/docs):
+Full documentation is available at [stackpanel.dev](https://stackpanel.dev/docs):
-- [Quick Start Guide](https://stack.dev/docs/quick-start)
-- [Concepts](https://stack.dev/docs/concepts)
-- [Configuration Reference](https://stack.dev/docs/reference)
-- [Secrets Management](https://stack.dev/docs/features/secrets)
-- [AWS Integration](https://stack.dev/docs/features/aws)
+- [Quick Start Guide](https://stackpanel.dev/docs/quick-start)
+- [Concepts](https://stackpanel.dev/docs/concepts)
+- [Configuration Reference](https://stackpanel.dev/docs/reference)
+- [Secrets Management](https://stackpanel.dev/docs/features/secrets)
+- [AWS Integration](https://stackpanel.dev/docs/features/aws)
## Architecture
diff --git a/apps/docs/content/docs/contributing.mdx b/apps/docs/content/docs/contributing.mdx
index 59a98eb9..379c4fe5 100644
--- a/apps/docs/content/docs/contributing.mdx
+++ b/apps/docs/content/docs/contributing.mdx
@@ -9,12 +9,12 @@ icon: heart
```bash
tmpdir=$(mktemp -d)
cd $tmpdir
-nix flake init -t github:darkmatter/stackpanel#minimal
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#minimal
# or locally
nix flake init -t /Users/coopermaruyama/darkmatter/stackpanel#default
git init && git add -A
-# 4. Update the flake to use local stackpanel (since github:darkmatter/stackpanel isn't public)
-sed 's|github:darkmatter/stackpanel|path:/Users/coopermaruyama/darkmatter/stackpanel|' flake.nix > flake.nix.tmp && mv flake.nix.tmp flake.nix
+# 4. Update the flake to use local stackpanel (since git+ssh://git@github.com/darkmatter/stackpanel isn't public)
+sed 's|git+ssh://git@github.com/darkmatter/stackpanel|path:/Users/coopermaruyama/darkmatter/stackpanel|' flake.nix > flake.nix.tmp && mv flake.nix.tmp flake.nix
```
\ No newline at end of file
diff --git a/apps/docs/content/docs/install.mdx b/apps/docs/content/docs/install.mdx
index 85588e1f..20f11888 100644
--- a/apps/docs/content/docs/install.mdx
+++ b/apps/docs/content/docs/install.mdx
@@ -11,5 +11,5 @@ Add to your `devenv.yaml`:
```yaml
inputs:
stackpanel:
- url: github:darkmatter/stackpanel
+ url: git+ssh://git@github.com/darkmatter/stackpanel
```
\ No newline at end of file
diff --git a/apps/docs/content/docs/quick-start.mdx b/apps/docs/content/docs/quick-start.mdx
index f88dc7ce..c8ea8693 100644
--- a/apps/docs/content/docs/quick-start.mdx
+++ b/apps/docs/content/docs/quick-start.mdx
@@ -40,7 +40,7 @@ If you're new to Nix, we recommend using the [Determinate Nix Installer](https:/
```bash
-nix flake init -t github:darkmatter/stackpanel
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel
```
This creates:
@@ -51,7 +51,7 @@ This creates:
```bash
-nix flake init -t github:darkmatter/stackpanel#devenv
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#devenv
```
This creates:
@@ -64,7 +64,7 @@ For users who prefer `devenv shell` over `nix develop`.
```bash
-nix flake init -t github:darkmatter/stackpanel#minimal
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#minimal
```
This creates:
@@ -86,7 +86,7 @@ Or add to an existing project manually:
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
devenv.url = "github:cachix/devenv";
- stackpanel.url = "github:darkmatter/stackpanel";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
nix2container.url = "github:nlewo/nix2container";
nix2container.inputs.nixpkgs.follows = "nixpkgs";
mk-shell-bin.url = "github:rrbutani/nix-mk-shell-bin";
diff --git a/apps/docs/src/app/(home)/page.tsx b/apps/docs/src/app/(home)/page.tsx
index 62a95184..18209bfe 100644
--- a/apps/docs/src/app/(home)/page.tsx
+++ b/apps/docs/src/app/(home)/page.tsx
@@ -122,7 +122,7 @@ export default function HomePage() {
{`inputs:
stackpanel:
- url: github:darkmatter/stackpanel
+ url: git+ssh://git@github.com/darkmatter/stackpanel
imports:
- stackpanel`}
diff --git a/apps/stackpanel-go/cmd/cli/init.go b/apps/stackpanel-go/cmd/cli/init.go
index f818ae72..1cdfd107 100644
--- a/apps/stackpanel-go/cmd/cli/init.go
+++ b/apps/stackpanel-go/cmd/cli/init.go
@@ -1,7 +1,3 @@
-// init.go implements `stackpanel init`, which scaffolds a new project by
-// evaluating the stackpanel flake's initFiles output and writing templates
-// into a .stack/ directory.
-
package cmd
import (
@@ -17,24 +13,24 @@ import (
"github.com/spf13/cobra"
)
-// defaultStackpanelFlake is the remote flake used to fetch init templates.
-// Override with --flake or STACKPANEL_FLAKE for local development.
-const defaultStackpanelFlake = "github:darkmatter/stackpanel"
+// Default flake reference for stackpanel
+// Users can override with --flake flag or STACKPANEL_FLAKE env var
+const defaultStackpanelFlake = "git+ssh://git@github.com/darkmatter/stackpanel"
var initCmd = &cobra.Command{
Use: "init",
Short: "Initialize a new stackpanel project",
- Long: `Initialize creates the .stack directory structure with boilerplate files.
+ Long: `Initialize creates the .stackpanel directory structure with boilerplate files.
This command evaluates the stackpanel flake to get the list of files to create,
then writes them to the appropriate locations. Existing files are NOT overwritten
unless --force is specified.
The initialized structure includes:
- - .stack/config.nix User-editable configuration file
- - .stack/_internal.nix Internal merging logic (do not edit)
- - .stack/data.nix Agent-editable data file
- - .stack/.gitignore Gitignore for state and local config
+ - .stackpanel/config.nix User-editable configuration file
+ - .stackpanel/_internal.nix Internal merging logic (do not edit)
+ - .stackpanel/data.nix Agent-editable data file
+ - .stackpanel/.gitignore Gitignore for state and local config
Example:
stackpanel init # Create files in current directory
@@ -53,7 +49,7 @@ var (
func init() {
initCmd.Flags().BoolVar(&initForce, "force", false, "Overwrite existing files")
initCmd.Flags().BoolVar(&initDryRun, "dry-run", false, "Show what would be created without writing files")
- initCmd.Flags().StringVar(&initFlake, "flake", "", "Stackpanel flake reference (default: github:darkmatter/stackpanel)")
+ initCmd.Flags().StringVar(&initFlake, "flake", "", "Stackpanel flake reference (default: git+ssh://git@github.com/darkmatter/stackpanel)")
rootCmd.AddCommand(initCmd)
}
@@ -62,7 +58,7 @@ func runInit(cmd *cobra.Command, args []string) error {
verbose, _ := cmd.Flags().GetBool("verbose")
ctx := context.Background()
- // Determine target directory (where to create .stack/)
+ // Determine target directory (where to create .stackpanel/)
targetDir, err := os.Getwd()
if err != nil {
return fmt.Errorf("failed to get current directory: %w", err)
@@ -77,6 +73,11 @@ func runInit(cmd *cobra.Command, args []string) error {
if flakeRef == "" {
flakeRef = os.Getenv("STACKPANEL_FLAKE")
}
+ if flakeRef == "" {
+ if root := os.Getenv("STACKPANEL_ROOT"); root != "" {
+ flakeRef = "path:" + root
+ }
+ }
if flakeRef == "" {
flakeRef = defaultStackpanelFlake
}
@@ -174,9 +175,9 @@ func runInit(cmd *cobra.Command, args []string) error {
if created > 0 {
fmt.Println()
output.Info("Next steps:")
- output.Dimmed(" 1. Review the generated files in .stack/")
- output.Dimmed(" 2. Edit .stack/config.nix to configure your project")
- output.Dimmed(" 3. Create a flake.nix that imports stackpanel (or use 'nix flake init -t github:darkmatter/stackpanel')")
+ output.Dimmed(" 1. Review the generated files in .stackpanel/")
+ output.Dimmed(" 2. Edit .stackpanel/config.nix to configure your project")
+ output.Dimmed(" 3. Create a flake.nix that imports stackpanel (or use 'nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel')")
output.Dimmed(" 4. Run 'nix develop --impure' to enter the dev shell")
}
}
@@ -184,9 +185,7 @@ func runInit(cmd *cobra.Command, args []string) error {
return nil
}
-// registerInitProject adds the initialized project to the user-global config
-// (~/.config/stackpanel/stackpanel.yaml). This lets the agent discover and
-// serve this project without requiring the user to be in its directory.
+// registerInitProject adds the initialized project to the user config.
func registerInitProject(projectRoot string) error {
ucm, err := userconfig.NewManager()
if err != nil {
@@ -206,14 +205,13 @@ func registerInitProject(projectRoot string) error {
// getInitFilesFromFlake evaluates initFiles from a stackpanel flake reference.
// The flakeRef can be:
-// - "github:darkmatter/stackpanel" (default, from GitHub)
+// - "git+ssh://git@github.com/darkmatter/stackpanel" (default, from GitHub)
// - "path:/local/path/to/stackpanel" (for local development)
// - "git+file:///local/path/to/stackpanel" (faster local, uses git filtering)
// - Any valid Nix flake reference
//
-// Gotcha: "path:" references copy the entire directory tree into the Nix store,
-// which is very slow for large repos. "git+file://" uses git's index to filter
-// to tracked files only, making it dramatically faster for local development.
+// Note: "path:" references are automatically converted to "git+file://" for better
+// performance (uses git to filter files instead of copying everything).
func getInitFilesFromFlake(ctx context.Context, flakeRef string) (map[string]string, error) {
// Convert path: to git+file:// for better performance
// path: copies the entire directory, git+file:// uses git to filter
@@ -225,9 +223,8 @@ func getInitFilesFromFlake(ctx context.Context, flakeRef string) (map[string]str
return nixeval.GetInitFilesFromFlake(ctx, flakeRef)
}
-// findProjectRoot walks up the directory tree to find the nearest project root.
-// A directory counts as a project root if it contains either flake.nix or
-// .stack/ — this covers both flake-based and standalone configurations.
+// findProjectRoot walks up the directory tree to find a project root
+// (directory containing flake.nix or .stackpanel)
func findProjectRoot() (string, error) {
dir, err := os.Getwd()
if err != nil {
@@ -239,15 +236,15 @@ func findProjectRoot() (string, error) {
if _, err := os.Stat(filepath.Join(dir, "flake.nix")); err == nil {
return dir, nil
}
- // Check for .stack
- if _, err := os.Stat(filepath.Join(dir, ".stack")); err == nil {
+ // Check for .stackpanel
+ if _, err := os.Stat(filepath.Join(dir, ".stackpanel")); err == nil {
return dir, nil
}
parent := filepath.Dir(dir)
if parent == dir {
// Reached root without finding project
- return "", fmt.Errorf("no project root found (looking for flake.nix or .stack)")
+ return "", fmt.Errorf("no project root found (looking for flake.nix or .stackpanel)")
}
dir = parent
}
diff --git a/apps/stackpanel-go/pkg/nixeval/eval.go b/apps/stackpanel-go/pkg/nixeval/eval.go
index 5451fde6..aea0c5a9 100644
--- a/apps/stackpanel-go/pkg/nixeval/eval.go
+++ b/apps/stackpanel-go/pkg/nixeval/eval.go
@@ -200,7 +200,7 @@ func EvalOnce(ctx context.Context, opts EvalOnceParams) ([]byte, error) {
}
timeout := opts.Timeout
if timeout <= 0 {
- timeout = 10 * time.Second
+ timeout = 10 * time.Minute
}
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
diff --git a/apps/stackpanel-go/pkg/nixeval/presets.go b/apps/stackpanel-go/pkg/nixeval/presets.go
index 72bdaea2..e1027416 100644
--- a/apps/stackpanel-go/pkg/nixeval/presets.go
+++ b/apps/stackpanel-go/pkg/nixeval/presets.go
@@ -11,19 +11,15 @@ import (
"time"
)
-// Preset Nix expressions for common evaluations.
-// These are self-contained snippets passed to `nix eval --impure --expr`.
-// They rely on STACKPANEL_ROOT being set (via builtins.getEnv) to locate
-// project files. The .stack/ path is tried first with .stackpanel/ as legacy fallback.
+// Preset Nix expressions for common evaluations
+// These are self-contained snippets that can be evaluated directly
const (
- // UsersPreset evaluates the users configuration from .stack/data or .stackpanel/data
+ // UsersPreset evaluates the users configuration from .stackpanel/data/users.nix
// Returns the users attrset in stackpanel.users format
UsersPreset = `
let
root = builtins.getEnv "STACKPANEL_ROOT";
- usersStack = root + "/.stack/data/users.nix";
- usersLegacy = root + "/.stackpanel/data/users.nix";
- usersPath = if builtins.pathExists usersStack then usersStack else usersLegacy;
+ usersPath = root + "/.stackpanel/data/users.nix";
in
if builtins.pathExists usersPath
then import usersPath
@@ -34,62 +30,31 @@ in
GitHubCollaboratorsPreset = `
let
root = builtins.getEnv "STACKPANEL_ROOT";
- collabsStack = root + "/.stack/data/github-collaborators.nix";
- collabsLegacy = root + "/.stackpanel/data/github-collaborators.nix";
- collabsPath = if builtins.pathExists collabsStack then collabsStack else collabsLegacy;
+ collabsPath = root + "/.stackpanel/data/github-collaborators.nix";
in
if builtins.pathExists collabsPath
then import collabsPath
else { collaborators = {}; }
`
- // StackpanelConfigPreset evaluates the full stackpanel config from .stack or .stackpanel.
- // Note: config.nix may be a plain attrset or a function taking { pkgs, lib, ... }.
- // We pass nulls for pkgs/lib since this lightweight eval can't provide them --
- // configs that depend on pkgs won't work here (use the flake-based presets instead).
+ // StackpanelConfigPreset evaluates the full stackpanel config from .stackpanel/config.nix
StackpanelConfigPreset = `
let
root = builtins.getEnv "STACKPANEL_ROOT";
- configStack = root + "/.stack/config.nix";
- configLegacy = root + "/.stackpanel/config.nix";
- configPath = if builtins.pathExists configStack then configStack else configLegacy;
- rawConfig =
- if builtins.pathExists configPath
- then import configPath
- else {};
- evaluatedConfig =
- if builtins.isFunction rawConfig
- then rawConfig {
- pkgs = null;
- lib = null;
- inputs = {};
- self = null;
- config = evaluatedConfig;
- }
- else rawConfig;
+ configPath = root + "/.stackpanel/config.nix";
in
- evaluatedConfig.stackpanel or evaluatedConfig or {}
+ if builtins.pathExists configPath
+ then (import configPath { pkgs = null; lib = null; config = {}; inputs = {}; }).stackpanel or {}
+ else {}
`
- // StackpanelSerializablePreset evaluates the full config from the flake's top-level
- // output. Unlike the preset above, this goes through the full module system and
- // includes computed values (ports, URLs, commands). Requires a valid flake.nix.
+ // StackpanelSerializablePreset evaluates the serializable config from the flake output
+ // This includes computed values like devshell._commandsSerializable
StackpanelSerializablePreset = `.#stackpanelConfig`
- // ActiveConfigPreset reads the config attached to the default devshell's passthru.
- // This is the canonical path for user projects that consume stackpanel as a flake input.
+ // ActiveConfig returns the current active stackpanel configuration as JSON (evaluated)
ActiveConfigPreset = `.#devShells.${builtins.currentSystem}.default.passthru.moduleConfig.stackpanel`
- // InitFilesPreset evaluates the db module to get boilerplate files for project scaffolding
- // Returns a map of relative paths to file contents
- InitFilesPreset = `
-let
- root = builtins.getEnv "STACKPANEL_ROOT";
- dbModule = import (root + "/nix/stackpanel/db") { };
-in
- dbModule.initFiles
-`
-
// DbSchemasPreset evaluates all schemas from the db module for codegen
// Returns a map of entity names to JSON Schema
DbSchemasPreset = `
@@ -101,10 +66,11 @@ in
`
)
-// InstalledPackagesExpr builds a Nix expression that extracts the package list
-// from a flake. It bakes the absolute projectRoot into the expression as a
-// git+file:// URI -- this avoids copying the entire worktree into the Nix store
-// (which would include node_modules, .git, etc.) and makes evaluation much faster.
+// InstalledPackagesExpr builds a Nix expression to get installed packages from a flake.
+// Tries devshell passthru first (for user projects consuming stackpanel), then falls back
+// to flake outputs (for stackpanel repo itself).
+// The projectRoot is baked directly into the expression to avoid relying on environment variables.
+// Uses git+file:// protocol to avoid copying untracked files (node_modules, etc.)
func InstalledPackagesExpr(projectRoot string) string {
return fmt.Sprintf(`
let
@@ -124,25 +90,24 @@ in
`, projectRoot)
}
-// EvalExprResult holds the raw JSON bytes from a nix eval invocation.
-// Use [EvalExprResult.Unmarshal] to decode into a typed Go struct.
+// EvalExprResult holds the raw JSON result of a Nix expression evaluation
type EvalExprResult struct {
Raw json.RawMessage
}
-// Unmarshal decodes the raw JSON into the provided value.
+// Unmarshal decodes the result into the provided type
func (r *EvalExprResult) Unmarshal(v interface{}) error {
return json.Unmarshal(r.Raw, v)
}
-// findNixBin locates the nix binary. PATH is checked first; if that fails
-// (e.g. running from a non-interactive context like launchd or systemd),
-// common Nix installation paths are tried as a fallback.
+// findNixBin locates the nix binary, checking PATH first then common locations
func findNixBin() (string, error) {
+ // Check PATH first
if path, err := exec.LookPath("nix"); err == nil {
return path, nil
}
+ // Check common locations
commonPaths := []string{
"/nix/var/nix/profiles/default/bin/nix",
"/run/current-system/sw/bin/nix",
@@ -258,9 +223,8 @@ func GetGitHubCollaborators(ctx context.Context) (*GitHubCollaboratorsData, erro
return &data, nil
}
-// GetStackpanelConfig evaluates the stackpanel section from .stack/config.nix.
-// This is a lightweight eval that passes null for pkgs/lib, so configs using
-// pkgs (e.g. for package references) will fail. Use the flake-based path for full eval.
+// GetStackpanelConfig evaluates the stackpanel section from .stackpanel/config.nix
+// Note: This is a simplified evaluation that doesn't have access to pkgs/lib
func GetStackpanelConfig(ctx context.Context) (map[string]interface{}, error) {
result, err := EvalExpr(ctx, StackpanelConfigPreset)
if err != nil {
@@ -275,35 +239,18 @@ func GetStackpanelConfig(ctx context.Context) (map[string]interface{}, error) {
return config, nil
}
-// GetInitFiles evaluates the db module and returns the map of paths to content
-// for scaffolding a new project.
-// DEPRECATED: Use GetInitFilesFromFlake instead for portable scaffolding.
-func GetInitFiles(ctx context.Context) (map[string]string, error) {
- result, err := EvalExpr(ctx, InitFilesPreset)
- if err != nil {
- return nil, fmt.Errorf("failed to evaluate initFiles: %w", err)
- }
-
- var files map[string]string
- if err := result.Unmarshal(&files); err != nil {
- return nil, fmt.Errorf("failed to parse initFiles: %w", err)
- }
-
- return files, nil
-}
-
// GetInitFilesFromFlake evaluates initFiles from a stackpanel flake reference.
// This is the portable way to get scaffold templates - works from any directory.
//
// The flakeRef can be:
-// - "github:darkmatter/stackpanel" (from GitHub)
+// - "git+ssh://git@github.com/darkmatter/stackpanel" (from GitHub)
// - "path:/local/path/to/stackpanel" (for local development)
// - Any valid Nix flake reference
//
// Example:
//
-// files, err := GetInitFilesFromFlake(ctx, "github:darkmatter/stackpanel")
-// // files[".stack/config.nix"] = "..."
+// files, err := GetInitFilesFromFlake(ctx, "git+ssh://git@github.com/darkmatter/stackpanel")
+// // files[".stackpanel/config.nix"] = "..."
func GetInitFilesFromFlake(ctx context.Context, flakeRef string) (map[string]string, error) {
// Evaluate #lib.initFiles
flakeAttr := flakeRef + "#lib.initFiles"
@@ -365,15 +312,12 @@ func GetDbSchemas(ctx context.Context) (map[string]interface{}, error) {
return schemas, nil
}
-// BuildExpr performs simple ${key} substitution on a Nix expression template.
-// Values are escaped for safe embedding in Nix double-quoted strings (backslashes,
-// quotes, and ${ interpolation sequences are all escaped).
-//
-// This is intentionally not a full template engine -- for complex expressions,
-// prefer --argstr or build the expression programmatically.
+// BuildExpr builds a Nix expression from a template with variables
+// Variables are substituted as string interpolations
func BuildExpr(template string, vars map[string]string) string {
result := template
for k, v := range vars {
+ // Escape the value for Nix string embedding
escaped := strings.ReplaceAll(v, "\\", "\\\\")
escaped = strings.ReplaceAll(escaped, "\"", "\\\"")
escaped = strings.ReplaceAll(escaped, "${", "\\${")
@@ -398,19 +342,16 @@ type GetInstalledPackagesOptions struct {
ConfigJSONPath string
}
-// GetInstalledPackages returns the list of packages in the devshell. It uses
-// a waterfall of increasingly expensive strategies:
-//
-// 1. Explicit configJSONPath (from options)
+// GetInstalledPackages returns the list of installed packages from the devshell configuration.
+// It tries multiple fast paths before falling back to slow nix eval:
+// 1. Explicit configJSONPath (if provided in options)
// 2. STACKPANEL_CONFIG_JSON env var (pre-computed at shell entry)
-// 3. State file at .stack/profile/stackpanel.json
-// 4. Generated config at .stack/gen/config.json
-// 5. Raw packages.nix data file (user-installed only, no devshell packages)
-// 6. Full flake evaluation (slow -- may download from caches, 5min timeout)
+// 3. State file at .stackpanel/state/stackpanel.json
+// 4. Generated config at .stackpanel/gen/config.json
+// 5. Nix eval against the flake (slow, last resort)
//
-// The fast paths (1-4) read pre-generated JSON from disk. The slow path (6)
-// evaluates the actual flake, which triggers a full Nix build if the evaluation
-// requires IFD (import-from-derivation).
+// If projectRoot is empty, it will attempt to find it from STACKPANEL_ROOT env var
+// or by searching up from the current directory.
func GetInstalledPackages(ctx context.Context, opts GetInstalledPackagesOptions) ([]InstalledPackage, error) {
projectRoot := opts.ProjectRoot
@@ -435,23 +376,21 @@ func GetInstalledPackages(ctx context.Context, opts GetInstalledPackagesOptions)
}
}
- // Fast path 3: try state file (.stack/profile then .stackpanel/state)
+ // Fast path 3: try state file
if projectRoot != "" {
- for _, p := range []string{projectRoot + "/.stack/profile/stackpanel.json", projectRoot + "/.stackpanel/state/stackpanel.json"} {
- packages, err := getInstalledPackagesFromJSON(p)
- if err == nil && len(packages) > 0 {
- return packages, nil
- }
+ stateFile := projectRoot + "/.stackpanel/state/stackpanel.json"
+ packages, err := getInstalledPackagesFromJSON(stateFile)
+ if err == nil && len(packages) > 0 {
+ return packages, nil
}
}
- // Fast path 4: try generated config (.stack/gen then .stackpanel/gen)
+ // Fast path 4: try generated config
if projectRoot != "" {
- for _, p := range []string{projectRoot + "/.stack/gen/config.json", projectRoot + "/.stackpanel/gen/config.json"} {
- packages, err := getInstalledPackagesFromJSON(p)
- if err == nil && len(packages) > 0 {
- return packages, nil
- }
+ genConfig := projectRoot + "/.stackpanel/gen/config.json"
+ packages, err := getInstalledPackagesFromJSON(genConfig)
+ if err == nil && len(packages) > 0 {
+ return packages, nil
}
}
@@ -502,16 +441,15 @@ func getInstalledPackagesFromJSON(configPath string) ([]InstalledPackage, error)
return config.Packages, nil
}
-// getUserPackagesFromDataFile reads user-installed packages from .stack/data or .stackpanel/data
+// getUserPackagesFromDataFile reads user-installed packages from .stackpanel/data/packages.nix
// This is a fallback when the config JSON doesn't have packages or doesn't exist yet.
// The file format is a simple Nix list of attribute path strings:
//
// [ "ripgrep" "jq" "htop" ]
func getUserPackagesFromDataFile(projectRoot string) ([]InstalledPackage, error) {
- packagesFile := projectRoot + "/.stack/data/packages.nix"
- if _, err := os.Stat(packagesFile); os.IsNotExist(err) {
- packagesFile = projectRoot + "/.stackpanel/data/packages.nix"
- }
+ packagesFile := projectRoot + "/.stackpanel/data/packages.nix"
+
+ // Check if file exists
if _, err := os.Stat(packagesFile); os.IsNotExist(err) {
return nil, err
}
@@ -553,9 +491,8 @@ func getUserPackagesFromDataFile(projectRoot string) ([]InstalledPackage, error)
return packages, nil
}
-// GetInstalledPackageNames returns a set of lowercased package names and attr
-// paths for O(1) membership checks. Both Name and AttrPath are indexed so
-// lookups work regardless of which identifier the caller has.
+// GetInstalledPackageNames returns just the package names as a set for fast lookup.
+// If projectRoot is empty, it will attempt to find it automatically.
func GetInstalledPackageNames(ctx context.Context, opts GetInstalledPackagesOptions) (map[string]bool, error) {
packages, err := GetInstalledPackages(ctx, opts)
if err != nil {
diff --git a/apps/web/src/components/agent-connect.tsx b/apps/web/src/components/agent-connect.tsx
index 41526ccc..9331d8fe 100644
--- a/apps/web/src/components/agent-connect.tsx
+++ b/apps/web/src/components/agent-connect.tsx
@@ -229,7 +229,7 @@ export function AgentConnect({ onConnected }: AgentConnectProps) {
- nix profile install github:darkmatter/stackpanel
+ nix profile install git+ssh://git@github.com/darkmatter/stackpanel
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 882590d9..0f8a211e 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -1,10 +1,10 @@
-# Stack Architecture
+# Stackpanel Architecture
-This document describes the internal architecture of Stack for contributors and those interested in understanding how the system works.
+This document describes the internal architecture of Stackpanel for contributors and those interested in understanding how the system works.
## Overview
-Stack is a Nix-based development environment framework that provides deterministic dev environments, service orchestration, secrets management, IDE integration, and a web-based studio for managing everything.
+Stackpanel is a Nix-based development environment framework that provides deterministic dev environments, service orchestration, secrets management, IDE integration, and a web-based studio for managing everything.
## Runtime Architecture
@@ -42,7 +42,7 @@ Browser (Studio UI)
### Core Design: Adapter-Agnostic Core + Thin Adapters
-All stack logic lives in `nix/stack/` and has zero dependency on devenv, NixOS, or any other module system. Adapters translate the core outputs to their target:
+All stackpanel logic lives in `nix/stackpanel/` and has zero dependency on devenv, NixOS, or any other module system. Adapters translate the core outputs to their target:
- `nix/flake/default.nix` - flake-parts adapter
- `nix/flake/modules/devenv.nix` - devenv adapter
@@ -53,32 +53,32 @@ All stack logic lives in `nix/stack/` and has zero dependency on devenv, NixOS,
```
User's flake.nix
-> imports flakeModules.default (nix/flake/default.nix)
- -> auto-loads .stack/_internal.nix
- -> lib.evalModules with nix/stack/ (the core)
- -> optionally imports .stack/devenv.nix into devenv.shells.default
+ -> auto-loads .stackpanel/_internal.nix
+ -> lib.evalModules with nix/stackpanel/ (the core)
+ -> optionally imports .stackpanel/devenv.nix into devenv.shells.default
-> creates devShells.default via pkgs.mkShell
```
### Option Namespaces
-All options are under `options.stack.*`:
+All options are under `options.stackpanel.*`:
| Namespace | Purpose |
|-----------|---------|
-| `stack.{enable, name, root, dirs}` | Project identity and paths |
-| `stack.apps` / `stack.appsComputed` | App definitions and computed ports/URLs |
-| `stack.ports` | Deterministic port computation config |
-| `stack.services` | Canonical service type system |
-| `stack.globalServices` | Convenience service definitions (postgres, redis, minio) |
-| `stack.devshell` | Shell environment (packages, hooks, env, files) |
-| `stack.scripts` | Shell commands |
-| `stack.modules` | Extension module registry |
-| `stack.secrets` | Master-key secrets management |
-| `stack.ide` | VS Code and Zed integration |
-| `stack.theme` | Starship prompt theming |
-| `stack.step-ca` | Certificate management |
-| `stack.aws` | AWS Roles Anywhere |
-| `stack.process-compose` | Process orchestration |
+| `stackpanel.{enable, name, root, dirs}` | Project identity and paths |
+| `stackpanel.apps` / `stackpanel.appsComputed` | App definitions and computed ports/URLs |
+| `stackpanel.ports` | Deterministic port computation config |
+| `stackpanel.services` | Canonical service type system |
+| `stackpanel.globalServices` | Convenience service definitions (postgres, redis, minio) |
+| `stackpanel.devshell` | Shell environment (packages, hooks, env, files) |
+| `stackpanel.scripts` | Shell commands |
+| `stackpanel.modules` | Extension module registry |
+| `stackpanel.secrets` | Master-key secrets management |
+| `stackpanel.ide` | VS Code and Zed integration |
+| `stackpanel.theme` | Starship prompt theming |
+| `stackpanel.step-ca` | Certificate management |
+| `stackpanel.aws` | AWS Roles Anywhere |
+| `stackpanel.process-compose` | Process orchestration |
## Deterministic Port System
@@ -99,21 +99,21 @@ Environment variables: `STACKPANEL__PORT` (e.g., `STACKPANEL_POSTGRES_PORT=
- **Framework**: TanStack Start (SSR-capable React) + Vite + Cloudflare Workers
- **Router**: TanStack Router with file-based routing
- **State**: TanStack Query with SuperJSON serialization
-- **Cloud API**: tRPC via `@stack/api`
+- **Cloud API**: tRPC via `@stackpanel/api`
- **Agent API**: Dual protocol - HTTP REST and Connect-RPC
- **Auth**: Better-Auth client with JWT session management
- **UI**: Radix UI primitives + shadcn components + Tailwind CSS v4
-### apps/stack-go/ - CLI + Agent (Go)
+### apps/stackpanel-go/ - CLI + Agent (Go)
Single Go binary with two modes:
**CLI** (Cobra commands):
-- `stack` - Interactive TUI navigator (default)
-- `stack services {start,stop,status,restart,logs}` - Service management
-- `stack caddy {start,stop,status,add,remove}` - Reverse proxy
-- `stack status` - Status dashboard
-- `stack agent` - Start the HTTP agent server
+- `stackpanel` - Interactive TUI navigator (default)
+- `stackpanel services {start,stop,status,restart,logs}` - Service management
+- `stackpanel caddy {start,stop,status,add,remove}` - Reverse proxy
+- `stackpanel status` - Status dashboard
+- `stackpanel agent` - Start the HTTP agent server
**Agent** (localhost HTTP server, port 9876):
- JWT auth via popup pairing flow
@@ -131,11 +131,11 @@ Single Go binary with two modes:
```
apps/web
- -> @stack/api (tRPC routers + types)
- -> @stack/auth (Better Auth + Polar payments)
- -> @stack/db (Drizzle ORM + Neon PostgreSQL)
- -> @stack/agent-client -> @stack/proto (Connect-RPC types)
- -> @stack/ui-web (shadcn components) -> @stack/ui-core (cn, cva, Logo) + @radix-ui/*
+ -> @stackpanel/api (tRPC routers + types)
+ -> @stackpanel/auth (Better Auth + Polar payments)
+ -> @stackpanel/db (Drizzle ORM + Neon PostgreSQL)
+ -> @stackpanel/agent-client -> @stackpanel/proto (Connect-RPC types)
+ -> @stackpanel/ui -> @stackpanel/ui-web -> @stackpanel/ui-core + @stackpanel/ui-primitives
```
## Secrets Architecture
@@ -146,7 +146,7 @@ Three-tier system:
2. **SOPS-encrypted YAML**: Per-environment files (`dev.yaml`, `staging.yaml`, `prod.yaml`)
3. **Agenix**: Per-secret `.age` files encrypted to team member SSH public keys
-## .stack/ Configuration
+## .stackpanel/ Configuration
### Files
@@ -163,7 +163,7 @@ Three-tier system:
| Path | Purpose |
|------|---------|
-| `state/stack.json` | Runtime state |
+| `state/stackpanel.json` | Runtime state |
| `state/shellhook.sh` | Generated shell hook |
| `state/starship.toml` | Generated prompt config |
| `gen/ide/vscode/` | VS Code workspace + devshell loader |
@@ -179,7 +179,7 @@ Three-tier system:
## Key Conventions
-- Nix modules implement behavior once in `nix/stack/lib/`, called from thin adapter modules
+- Nix modules implement behavior once in `nix/stackpanel/lib/`, called from thin adapter modules
- The Go CLI is the single writer for generated files (avoids symlink issues, ensures atomicity)
- Proto definitions in `packages/proto/` are the contract between Go agent and TypeScript web app
- Environment variables follow the pattern `STACKPANEL__`
@@ -191,36 +191,32 @@ Plugins are just flake inputs:
```nix
inputs = {
- stack.url = "github:darkmatter/stack";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
# Community plugins
- stack-aws.url = "github:someone/stack-aws";
- stack-stripe.url = "github:someone/stack-stripe";
+ stackpanel-aws.url = "github:someone/stackpanel-aws";
+ stackpanel-stripe.url = "github:someone/stackpanel-stripe";
};
imports = [
- inputs.stack.flakeModules.default
- inputs.stack-aws.flakeModules.default
+ inputs.stackpanel.flakeModules.default
+ inputs.stackpanel-aws.flakeModules.default
];
```
## Directory Structure
```
-nix/stack/
- core/ # Core schema, CLI invocation, state, utilities
- options/ # Centralized option definitions (multi-consumer options only)
- lib/ # Pure service library functions (mkGlobalServices, etc.)
- cli.nix # CLI-based file generation (includes cli options)
- state.nix # Legacy state file generation (includes state options)
+nix/stackpanel/
+ core/ # Options definitions, CLI invocation, state, utilities
devshell/ # Shell subsystem (scripts, files, codegen, bin wrappers)
- network/ # Step CA certificates, port env vars, DNS (includes dns options)
- services/ # Service implementations (postgres, redis, caddy, aws, binary-cache w/ options)
+ network/ # Step CA certificates, port env vars
+ services/ # Service implementations (postgres, redis, caddy, aws)
secrets/ # Master-key encryption (agenix, SOPS, combined)
ide/ # VS Code and Zed file generation
modules/ # Auto-discovered directory modules
- lib/ # Pure library functions (ports, theme, IDE, paths)
- apps/ # App-level features and CI (includes ci options)
- tui/ # Terminal UI theme (includes theme options)
+ lib/ # Pure library functions
+ apps/ # App-level features and CI
+ tui/ # Terminal UI theme
packages/ # Nix package definitions
```
diff --git a/docs/MODULE_BOILERPLATE_INJECTION.md b/docs/MODULE_BOILERPLATE_INJECTION.md
index e78e281d..dbcd2648 100644
--- a/docs/MODULE_BOILERPLATE_INJECTION.md
+++ b/docs/MODULE_BOILERPLATE_INJECTION.md
@@ -2,16 +2,16 @@
## Overview
-When users install a stack module (via CLI or web UI), the module's configuration boilerplate is automatically injected into their config files. This provides a smooth onboarding experience with commented examples ready to customize.
+When users install a stackpanel module (via CLI or web UI), the module's configuration boilerplate is automatically injected into their config files. This provides a smooth onboarding experience with commented examples ready to customize.
## Architecture
### 1. Automatic Detection on Shell Entry
Modules can be installed via:
-- **Flake inputs**: `inputs.stack-oxlint.url = "github:...";`
-- **Built-in modules**: Already in `nix/stack/modules/`
-- **Local modules**: In `.stack/modules/`
+- **Flake inputs**: `inputs.stackpanel-oxlint.url = "github:...";`
+- **Built-in modules**: Already in `nix/stackpanel/modules/`
+- **Local modules**: In `.stackpanel/modules/`
The injection system automatically detects changes and updates config files on every shell entry.
@@ -24,7 +24,7 @@ Each module defines a `configBoilerplate` field in its `meta.nix`:
id = "oxlint";
name = "OxLint";
description = "Blazing fast JavaScript/TypeScript linter";
-
+
# Boilerplate to inject into user's config
configBoilerplate = ''
# OxLint - Blazing fast JavaScript/TypeScript linter
@@ -39,7 +39,7 @@ Each module defines a `configBoilerplate` field in its `meta.nix`:
### 3. Nix-Generated Manifest
-During Nix evaluation, stack generates a modules manifest at `.stack/gen/modules-manifest.json`:
+During Nix evaluation, stackpanel generates a modules manifest at `.stackpanel/gen/modules-manifest.json`:
```json
{
@@ -63,24 +63,24 @@ During Nix evaluation, stack generates a modules manifest at `.stack/gen/modules
This manifest is generated from:
- All available modules (built-in + flake inputs + local)
-- Their current enabled/disabled state from `stack.modules.*`
+- Their current enabled/disabled state from `stackpanel.modules.*`
- Their boilerplate text from `meta.nix`
### 4. Injection Markers
Configuration files use special marker comments to define injection zones:
-**In `.stack/config.nix`:**
+**In `.stackpanel/config.nix`:**
```nix
{
# ... user config ...
# 5. Injection Algorithm (Automatic on Shell Entry)
-On every shell entry, `stack init` runs:
+On every shell entry, `stackpanel init` runs:
-1. **Read** the generated manifest at `.stack/gen/modules-manifest.json`
-2. **Compare** with previous injection state (stored in `.stack/state/modules-injected.json`)
+1. **Read** the generated manifest at `.stackpanel/gen/modules-manifest.json`
+2. **Compare** with previous injection state (stored in `.stackpanel/state/modules-injected.json`)
3. **If changed**:
- Parse config files to find injection markers
- Rebuild injection zones with current modules (alphabetically sorted)
@@ -91,7 +91,7 @@ On every shell entry, `stack init` runs:
**Nix side** (in shell hook or file generation):
```nix
# Generate modules manifest
-stack.files.entries."gen/modules-manifest.json" = {
+stackpanel.files.entries."gen/modules-manifest.json" = {
type = "text";
text = builtins.toJSON {
version = 1;
@@ -100,7 +100,7 @@ stack.files.entries."gen/modules-manifest.json" = {
name = mod.name or id;
enabled = mod.enable or false;
configBoilerplate = mod.meta.configBoilerplate or "";
- }) stack.modulesComputed;
+ }) stackpanel.modulesComputed;
};
};
```
@@ -125,23 +125,23 @@ func SyncModuleBoilerplates(manifestPath, configPath, statePath string) error {
if err != nil {
return err
}
-
+
// 2. Read previous state
prevState, _ := readState(statePath) // ignore error if first run
-
+
// 3. Check if changed
if manifestsEqual(manifest, prevState) {
return nil // Fast path: no changes
}
-
+
// 4. Get enabled modules only
enabled := filterEnabled(manifest.Modules)
-
+
// 5. Inject into config files
if err := injectToFile(configPath, enabled); err != nil {
return err
}
-
+
// 6. Save new state
return saveState(statePath, manifest)
}
@@ -149,7 +149,7 @@ func SyncModuleBoilerplates(manifestPath, configPath, statePath string) error {
func injectToFile(path string, modules []ModuleMetadata) error {
content, _ := os.ReadFile(path)
before, _, after := parseInjectionZone(string(content))
-
+
// Build injection content
6. User Workflow
@@ -159,11 +159,11 @@ func injectToFile(path string, modules []ModuleMetadata) error {
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- stack.url = "github:darkmatter/stack";
- stack-oxlint.url = "github:stack-modules/oxlint"; # ← Add module
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
+ stackpanel-oxlint.url = "github:stackpanel-modules/oxlint"; # ← Add module
};
-
- outputs = { stack, stack-oxlint, ... }: {
+
+ outputs = { stackpanel, stackpanel-oxlint, ... }: {
# Module is automatically available
};
}
@@ -171,7 +171,7 @@ func injectToFile(path string, modules []ModuleMetadata) error {
**Or enabling a built-in module:**
```nix
-# .stack/config.nix or .stack/data/modules.nix
+# .stackpanel/config.nix or .stackpanel/data/modules.nix
{
oxlint.enable = true; # ← Enable built-in module
}
@@ -180,14 +180,14 @@ func injectToFile(path string, modules []ModuleMetadata) error {
**On next shell entry** (`nix develop --impure`):
1. Nix re-evaluates and detects new module
2. Generates updated manifest with oxlint
-3. Shell hook runs `stack init`
+3. Shell hook runs `stackpanel init`
4. CLI detects manifest change
5. Injects boilerplate automatically }
-
+
injected.WriteString(" # ---------------------------------------------------------------------------\n")
injected.WriteString(" # STACKPANEL_MODULES_END\n")
injected.WriteString(" # ---------------------------------------------------------------------------")
-
+
newContent := before + injected.String() + after
return os.WriteFile(p
ID string
@@ -200,22 +200,22 @@ func InjectModuleConfig(configPath string, module ModuleBoilerplate) error {
if err != nil {
return err
}
-
+
// 2. Parse sections
before, injected, after := parseInjectionZone(string(content))
-
+
// 3. Parse existing modules in injection zone
modules := parseModules(injected)
-
+
// 4. Add/update module
modules[module.ID] = module.Boilerplate
-
+
// 5. Sort by ID
sorted := sortModules(modules)
-
+
// 6. Rebuild injection zone
newInjected := buildInjectionZone(sorted)
-
+
// 7. Write back
newContent := before + newInjected + after
return os.WriteFile(configPath, []byte(newContent), 0644)
@@ -237,11 +237,11 @@ User edits **outside** the injection zone are preserved.
**Installing a module:**
```bash
-stack module install oxlint
+stackpanel module install oxlint
# or via web UI
```
-**Result in `.stack/data/modules.nix`:**
+**Result in `.stackpanel/data/modules.nix`:**
```nix
{
# ... manual configs ...
@@ -249,7 +249,7 @@ stack module install oxlint
# ---------------------------------------------------------------------------
# STACKPANEL_MODULES_BEGIN
# Auto-generated module configurations (do not edit this section manually)
- # Modules are sorted alphabetically and injected by the stack CLI
+ # Modules are sorted alphabetically and injected by the stackpanel CLI
# ---------------------------------------------------------------------------
# OxLint - Blazing fast JavaScript/TypeScript linter
@@ -287,10 +287,10 @@ Modules can define boilerplate for multiple targets:
{
# Main config.nix injection
configBoilerplate = ''...'';
-
+
# Optional: data/modules.nix injection (if different)
dataBoilerplate = ''...'';
-
+
# Optional: per-app config injection
appBoilerplate = ''...'';
}
@@ -322,12 +322,12 @@ Sort order:
3. **Provide sensible defaults**: Make the config work with minimal edits
4. **Use clear comments**: Explain what each option does
5. **Follow Nix conventions**: Proper indentation, naming
-Add modules manifest generation to Nix (stack.files.entries)
+Add modules manifest generation to Nix (stackpanel.files.entries)
- [ ] Implement Go parser for injection zones
- [ ] Implement Go manifest reader and differ
- [ ] Implement Go injector (sync on shell entry)
-- [ ] Add to `stack init` command
-- [ ] Add state tracking (.stack/state/modules-injected.json)
+- [ ] Add to `stackpanel init` command
+- [ ] Add state tracking (.stackpanel/state/modules-injected.json)
- [ ] Test with real modules
- [ ] Add validation (ensure configs parse correctly)
- [ ] Add conflict detection (duplicate IDs)
@@ -336,13 +336,13 @@ Add modules manifest generation to Nix (stack.files.entries)
The injection runs as part of the shell entry process:
```nix
-# nix/stack/devshell/hooks.nix
-stack.devshell.hooks.main = ''
+# nix/stackpanel/devshell/hooks.nix
+stackpanel.devshell.hooks.main = ''
# ... existing hooks ...
-
+
# Sync module boilerplates if manifest changed
- if [[ -f .stack/gen/modules-manifest.json ]]; then
- stack init --sync-modules
+ if [[ -f .stackpanel/gen/modules-manifest.json ]]; then
+ stackpanel init --sync-modules
fi
'';
```
@@ -351,12 +351,12 @@ Or alternatively, the manifest generation itself triggers the sync:
```nix
# Generate manifest and trigger sync in one step
-stack.files.entries."gen/modules-manifest.json" = {
+stackpanel.files.entries."gen/modules-manifest.json" = {
type = "text";
text = builtins.toJSON manifestData;
# Post-write hook: sync boilerplates after manifest changes
onChange = ''
- ${pkgs.stack-cli}/bin/stack init --sync-modules
+ ${pkgs.stackpanel-cli}/bin/stackpanel init --sync-modules
'';
};
```
@@ -370,7 +370,7 @@ stack.files.entries."gen/modules-manifest.json" = {
5. **Diff preview**: Show what will be injected on shell entry (verbose mode)
- [ ] Implement Go parser for injection zones
- [ ] Implement Go injector/remover
-- [ ] Add CLI commands: `stack module install/uninstall`
+- [ ] Add CLI commands: `stackpanel module install/uninstall`
- [ ] Add web UI for module installation
- [ ] Add module registry API
- [ ] Test with real modules
diff --git a/nix/flake/exports.nix b/nix/flake/exports.nix
index be80dc28..837de363 100644
--- a/nix/flake/exports.nix
+++ b/nix/flake/exports.nix
@@ -245,11 +245,20 @@ in
# { ".stack/config.nix" = "..."; ... }
#
# Usage from CLI:
- # nix eval github:darkmatter/stackpanel#lib.initFiles --json
+ # nix eval git+ssh://git@github.com/darkmatter/stackpanel#lib.initFiles --json
#
# Usage from Nix:
# inputs.stackpanel.lib.initFiles
- initFiles = (import ../stackpanel/db { }).initFiles;
+ initFiles =
+ let
+ templateDir = ../flake/templates/default/.stackpanel;
+ in
+ {
+ ".stackpanel/config.nix" = builtins.readFile (templateDir + "/config.nix");
+ ".stackpanel/_internal.nix" = builtins.readFile (templateDir + "/_internal.nix");
+ ".stackpanel/.gitignore" = builtins.readFile (templateDir + "/.gitignore");
+ ".stackpanel/data.nix" = builtins.readFile (templateDir + "/data.nix");
+ };
# All schemas for codegen/introspection
# Usage: inputs.stackpanel.lib.schemas
diff --git a/nix/flake/templates/README.md b/nix/flake/templates/README.md
index 4e8eb705..b2386994 100644
--- a/nix/flake/templates/README.md
+++ b/nix/flake/templates/README.md
@@ -1,13 +1,13 @@
-# Stack Templates
+# Stackpanel Templates
-Project templates for bootstrapping new Stack projects.
+Project templates for bootstrapping new Stackpanel projects.
## Available Templates
| Template | Description | Use Case |
|----------|-------------|----------|
| `default` | devenv + flake-parts | Full-featured, recommended for most projects |
-| `native` | Native Nix shell + flake-parts | When you want Stack without devenv |
+| `native` | Native Nix shell + flake-parts | When you want Stackpanel without devenv |
| `devenv` | Standalone devenv.yaml | For devenv-first workflows (no flake.nix) |
| `minimal` | devenv without flake-parts | Simple flake without flake-parts |
@@ -18,10 +18,10 @@ Project templates for bootstrapping new Stack projects.
mkdir myproject && cd myproject
# Initialize from template (choose one)
-nix flake init -t github:darkmatter/stack # default
-nix flake init -t github:darkmatter/stack#native # native
-nix flake init -t github:darkmatter/stack#devenv # devenv
-nix flake init -t github:darkmatter/stack#minimal # minimal
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel # default
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#native # native
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#devenv # devenv
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#minimal # minimal
# Enter the dev environment
direnv allow # or: nix develop --impure
@@ -34,7 +34,7 @@ direnv allow # or: nix develop --impure
Full-featured setup with devenv and flake-parts integration.
```bash
-nix flake init -t github:darkmatter/stack
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel
```
**Structure:**
@@ -43,15 +43,15 @@ nix flake init -t github:darkmatter/stack
├── flake.nix # Flake entry with flake-parts
├── nix/
│ └── devenv.nix # Devenv options (packages, languages, etc.)
-├── .stack/
-│ └── config.nix # Stack options
+├── .stackpanel/
+│ └── config.nix # Stackpanel options
└── .envrc # direnv configuration
```
**Features:**
- Multi-platform support (Linux/Darwin, x86_64/aarch64)
- All devenv features (processes, services, languages)
-- All Stack features (CLI, IDE, theme, services)
+- All Stackpanel features (CLI, IDE, theme, services)
- Clean separation of concerns
---
@@ -61,22 +61,22 @@ nix flake init -t github:darkmatter/stack
Lightweight setup using native `mkShell` instead of devenv.
```bash
-nix flake init -t github:darkmatter/stack#native
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#native
```
**Structure:**
```
.
├── flake.nix # Flake with flakeModules.native
-├── .stack/
-│ └── config.nix # Stack options
+├── .stackpanel/
+│ └── config.nix # Stackpanel options
└── .envrc # direnv configuration
```
**Features:**
- Faster evaluation (no devenv dependency)
- Pure Nix implementation
-- All Stack features
+- All Stackpanel features
- No `devenv up` (use external process managers)
---
@@ -86,16 +86,16 @@ nix flake init -t github:darkmatter/stack#native
Standalone devenv setup without a flake.nix.
```bash
-nix flake init -t github:darkmatter/stack#devenv
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#devenv
```
**Structure:**
```
.
├── devenv.yaml # Devenv inputs and imports
-├── devenv.nix # Devenv + Stack options
-├── .stack/
-│ └── config.nix # Stack options
+├── devenv.nix # Devenv + Stackpanel options
+├── .stackpanel/
+│ └── config.nix # Stackpanel options
└── .envrc # direnv configuration
```
@@ -112,15 +112,15 @@ devenv up # Start processes
Traditional flake.nix without flake-parts.
```bash
-nix flake init -t github:darkmatter/stack#minimal
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#minimal
```
**Structure:**
```
.
├── flake.nix # Standard Nix flake
-├── .stack/
-│ └── config.nix # Stack options
+├── .stackpanel/
+│ └── config.nix # Stackpanel options
└── .envrc # direnv configuration
```
@@ -131,18 +131,18 @@ nix flake init -t github:darkmatter/stack#minimal
## Configuration
-All templates use the same `.stack/config.nix` structure:
+All templates use the same `.stackpanel/config.nix` structure:
```nix
{
enable = true;
-
+
# Shell prompt theme
theme.enable = true;
-
+
# VS Code integration
ide.vscode.enable = true;
-
+
# Global services
globalServices = {
postgres.enable = true;
@@ -153,7 +153,7 @@ All templates use the same `.stack/config.nix` structure:
## Learn More
-- [Stack Documentation](https://stack.dev/docs)
-- [Quick Start Guide](https://stack.dev/docs/quick-start)
+- [Stackpanel Documentation](https://stackpanel.dev/docs)
+- [Quick Start Guide](https://stackpanel.dev/docs/quick-start)
- [devenv Documentation](https://devenv.sh)
- [Flake Parts](https://flake.parts)
diff --git a/nix/flake/templates/_test-fixtures/README.md b/nix/flake/templates/_test-fixtures/README.md
index cee51162..7431ca1f 100644
--- a/nix/flake/templates/_test-fixtures/README.md
+++ b/nix/flake/templates/_test-fixtures/README.md
@@ -1,13 +1,13 @@
# Test Fixtures
-These fixtures are used for testing stack modules in CI. They are **not** meant for `nix flake init`.
+These fixtures are used for testing stackpanel modules in CI. They are **not** meant for `nix flake init`.
## Notes
-- Fixtures use SSH URLs (`git+ssh://git@github.com/darkmatter/stack`) which require SSH access to the repo
+- Fixtures use SSH URLs (`git+ssh://git@github.com/darkmatter/stackpanel`) which require SSH access to the repo
- Initial runs are slow due to fetching nixpkgs, flake-parts, etc. Subsequent runs use cached inputs
- Use `--no-write-lock-file` to avoid modifying the fixture's lock file
-- Override `stack` input with local path for development: `--override-input stack path:.`
+- Override `stackpanel` input with local path for development: `--override-input stackpanel path:.`
## Scenarios
@@ -18,64 +18,9 @@ These fixtures are used for testing stack modules in CI. They are **not** meant
| `full-stack` | Multiple apps (web, server, docs) | Multi-app handling, all modules enabled |
| `external-module` | Test external module | Module loading from flake input |
-## Snapshot Testing (Golden Files)
-
-Each fixture can include a `golden/` directory containing the expected generated file contents.
-When present, `nix flake check` will build the full file generation pipeline and `diff -r` the
-output against `golden/`, failing if anything has changed.
-
-This gives you end-to-end regression testing of the entire config → module evaluation → file
-generation pipeline with reviewable diffs in PRs.
-
-### How it works
-
-```
-.stack/config.nix (input: scenario configuration)
- ↓ full NixOS module evaluation
-stackpanelFullConfig.files (evaluated file entries)
- ↓ _storePathsByFile
-snapshot derivation (all file contents assembled into a directory)
- ↓ diff -ru
-golden/ (checked-in expected output)
-```
-
-### Generating golden files for the first time
-
-```bash
-# Generate golden/ for all fixtures
-./nix/flake/templates/_test-fixtures/update-golden.sh
-
-# Generate golden/ for specific fixtures
-./nix/flake/templates/_test-fixtures/update-golden.sh basic with-oxlint
-```
-
-### Updating golden files after a change
-
-When you intentionally change what files a module generates (new file, changed content, etc.),
-the snapshot check will fail with a unified diff showing exactly what changed. To accept the
-new output:
-
-```bash
-# Update the fixture(s) that changed
-./nix/flake/templates/_test-fixtures/update-golden.sh with-oxlint
-
-# Review and commit
-git diff nix/flake/templates/_test-fixtures/with-oxlint/golden/
-git add nix/flake/templates/_test-fixtures/with-oxlint/golden/
-```
-
-### Inspecting the snapshot without updating
-
-```bash
-# Build the snapshot derivation and browse its contents
-nix build ./nix/flake/templates/_test-fixtures/with-oxlint#snapshot \
- --override-input stack path:. --no-write-lock-file
-ls -la result/
-```
-
## Usage in CI
-### Testing stack itself
+### Testing stackpanel itself
```bash
# Using the test script (recommended)
@@ -87,7 +32,7 @@ ls -la result/
# Manual: Run all fixture checks
for fixture in nix/flake/templates/_test-fixtures/*/; do
echo "Testing $(basename $fixture)..."
- nix flake check "$fixture" --override-input stack path:. --no-write-lock-file
+ nix flake check "$fixture" --override-input stackpanel path:. --no-write-lock-file
done
```
@@ -97,7 +42,7 @@ Fixtures are exposed as flake templates for easy access:
```bash
# Initialize a test fixture
-nix flake init -t github:darkmatter/stack#test-external-module
+nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#test-external-module
# Override the module input with your module
nix flake lock --override-input test-module path:../my-module
@@ -117,29 +62,25 @@ nix flake check
```bash
# List all available templates
-nix flake show github:darkmatter/stack --json | jq '.templates | keys'
+nix flake show git+ssh://git@github.com/darkmatter/stackpanel --json | jq '.templates | keys'
```
## Creating New Fixtures
1. Copy an existing fixture as a starting point
-2. Modify `.stack/config.nix` for your scenario
+2. Modify `.stackpanel/config.nix` for your scenario
3. Add any test apps in `apps/` if needed
4. Add test checks in `flake.nix` if needed
-5. Run `./update-golden.sh ` to generate the `golden/` directory
-6. Commit the `golden/` directory — future `nix flake check` runs will validate against it
## Fixture Structure
```
fixture-name/
-├── flake.nix # Flake with stack + test checks
+├── flake.nix # Flake with stackpanel + test checks
├── flake.lock # Optional: lock file for reproducibility
-├── .stack/
-│ └── config.nix # Scenario configuration
-├── golden/ # Snapshot: expected generated file contents
-│ ├── .gitignore
-│ └── ...
+├── .stackpanel/
+│ ├── config.nix # Scenario configuration
+│ └── _internal.nix # Optional: internal config
└── apps/ # Optional: test apps
└── web/
├── src/
diff --git a/nix/flake/templates/default/flake.nix b/nix/flake/templates/default/flake.nix
index 60462a6c..2cfeadf0 100644
--- a/nix/flake/templates/default/flake.nix
+++ b/nix/flake/templates/default/flake.nix
@@ -4,7 +4,7 @@
# Starter flake template for projects using stackpanel.
#
# Getting started:
-# 1. Run: nix flake init -t github:darkmatter/stackpanel
+# 1. Run: nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel
# 2. Run: direnv allow
# 3. Configure stackpanel in ./.stack/config.nix
#
@@ -23,11 +23,17 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
- stackpanel.url = "github:darkmatter/stackpanel";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
};
outputs =
- { self, nixpkgs, flake-utils, stackpanel, ... }@inputs:
+ {
+ self,
+ nixpkgs,
+ flake-utils,
+ stackpanel,
+ ...
+ }@inputs:
# Use stackpanel.lib.mkFlake for full stackpanel integration
stackpanel.lib.mkFlake { inherit inputs self; }
# Merge with additional custom outputs
diff --git a/nix/flake/templates/devenv/devenv.yaml b/nix/flake/templates/devenv/devenv.yaml
index 027f740d..38d25ffa 100644
--- a/nix/flake/templates/devenv/devenv.yaml
+++ b/nix/flake/templates/devenv/devenv.yaml
@@ -11,7 +11,7 @@ inputs:
nixpkgs:
url: github:NixOS/nixpkgs/nixos-unstable
stackpanel:
- url: github:darkmatter/stackpanel
+ url: git+ssh://git@github.com/darkmatter/stackpanel
imports:
- stackpanel/devenvModules/default
diff --git a/nix/flake/templates/minimal/flake.nix b/nix/flake/templates/minimal/flake.nix
index 441d3b63..2ad92999 100644
--- a/nix/flake/templates/minimal/flake.nix
+++ b/nix/flake/templates/minimal/flake.nix
@@ -5,7 +5,7 @@
# Uses standard Nix flake structure with flake-utils.
#
# Getting started:
-# 1. Run: nix flake init -t github:darkmatter/stackpanel#minimal
+# 1. Run: nix flake init -t git+ssh://git@github.com/darkmatter/stackpanel#minimal
# 2. Run: direnv allow
# 3. Configure stackpanel in ./.stack/config.nix
# ==============================================================================
@@ -15,11 +15,17 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
- stackpanel.url = "github:darkmatter/stackpanel";
+ stackpanel.url = "git+ssh://git@github.com/darkmatter/stackpanel";
};
outputs =
- { self, nixpkgs, flake-utils, stackpanel, ... }@inputs:
+ {
+ self,
+ nixpkgs,
+ flake-utils,
+ stackpanel,
+ ...
+ }@inputs:
# Simple usage: just call mkFlake
stackpanel.lib.mkFlake { inherit inputs self; }
# Merge with your own outputs
diff --git a/nix/stackpanel/db/default.nix b/nix/stackpanel/db/default.nix
index d0a64dd4..121433cc 100644
--- a/nix/stackpanel/db/default.nix
+++ b/nix/stackpanel/db/default.nix
@@ -329,39 +329,6 @@ let
}
'';
- # ============================================================================
- #
- # INTERNAL: Scaffolding / init file generation
- #
- # Generates the .stack/ directory structure for new projects.
- # config.nix is the single source of truth (both user and agent editable).
- #
- # ============================================================================
- initFiles =
- let
- configBoilerplate = schemas.config.boilerplate or null;
- configFile = {
- ".stack/config.nix" =
- if configBoilerplate != null then
- configBoilerplate
- else
- ''
- # Stackpanel project configuration
- # See: https://stackpanel.dev/docs/config
- {
- enable = true;
- name = "my-project";
- github = "owner/repo";
- }
- '';
- };
-
- gitignoreBoilerplate = schemas.config.gitignoreBoilerplate or null;
- gitignoreFile =
- if gitignoreBoilerplate != null then { ".stack/.gitignore" = gitignoreBoilerplate; } else { };
-
- in
- configFile // gitignoreFile;
in
{
# ============================================================================
@@ -380,9 +347,6 @@ in
# Entity name lists
inherit entityNames dataEntityNames externalEntityNames;
- # Scaffolding
- inherit initFiles;
-
# Proto rendering
inherit render protoFiles protoFileMap;
diff --git a/nix/stackpanel/db/schemas/config.proto.nix b/nix/stackpanel/db/schemas/config.proto.nix
index 39639337..37d8f42d 100644
--- a/nix/stackpanel/db/schemas/config.proto.nix
+++ b/nix/stackpanel/db/schemas/config.proto.nix
@@ -2,10 +2,7 @@
# config.proto.nix
#
# Protobuf schema for Stackpanel project configuration.
-# This is the root configuration file at .stack/config.nix
-#
-# This file also contains boilerplate templates for scaffolding new projects.
-# The `stackpanel scaffold` command and `nix flake init` templates use these.
+# This is the root configuration file at .stackpanel/config.nix
# ==============================================================================
{ lib }:
let
@@ -15,194 +12,6 @@ proto.mkProtoFile {
name = "config.proto";
package = "stackpanel.db";
- # ==========================================================================
- # User-editable config.nix boilerplate
- # This is the main configuration file users edit
- # ==========================================================================
- boilerplate = ''
- # ==============================================================================
- # config.nix
- #
- # Stackpanel project configuration.
- # Edit this file to configure your project.
- # ==============================================================================
- {
- enable = true;
- name = "my-project";
- github = "owner/repo";
- # debug = false;
-
- # ---------------------------------------------------------------------------
- # CLI - Stackpanel command-line tools
- # ---------------------------------------------------------------------------
- cli.enable = true;
-
- # ---------------------------------------------------------------------------
- # Theme - Starship prompt with stackpanel styling
- # See: https://stackpanel.dev/docs/theme
- # ---------------------------------------------------------------------------
- theme.enable = true;
- # theme = {
- # name = "default";
- # nerd-font = true;
- # minimal = false;
- #
- # colors = {
- # primary = "#7aa2f7";
- # secondary = "#bb9af7";
- # success = "#9ece6a";
- # warning = "#e0af68";
- # error = "#f7768e";
- # muted = "#565f89";
- # };
- #
- # starship = {
- # add-newline = true;
- # scan-timeout = 30;
- # command-timeout = 500;
- # };
- # };
-
- # ---------------------------------------------------------------------------
- # IDE Integration - Auto-generate editor config files
- # ---------------------------------------------------------------------------
- ide.enable = true;
- ide.vscode.enable = true;
-
- # ---------------------------------------------------------------------------
- # MOTD - Message of the day shown on shell entry
- # ---------------------------------------------------------------------------
- motd.enable = true;
- motd.commands = [
- {
- name = "dev";
- description = "Start development server";
- }
- {
- name = "build";
- description = "Build the project";
- }
- ];
-
- # ---------------------------------------------------------------------------
- # Users - Team members with project access
- # GitHub team members are auto-imported from data/github-collaborators.nix.
- # Add overrides or additional users here.
- # See: https://stackpanel.dev/docs/users
- # ---------------------------------------------------------------------------
- # users = {
- # johndoe = {
- # name = "John Doe";
- # github = "johndoe";
- # email = "john@example.com";
- # };
- # };
-
- # ---------------------------------------------------------------------------
- # AWS - AWS Roles Anywhere for certificate-based authentication
- # See: https://stackpanel.dev/docs/aws
- # ---------------------------------------------------------------------------
- # aws = {
- # roles-anywhere = {
- # enable = true;
- # region = "us-east-1";
- # account-id = "123456789012";
- # role-name = "DeveloperRole";
- # trust-anchor-arn = "arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/...";
- # profile-arn = "arn:aws:rolesanywhere:us-east-1:123456789012:profile/...";
- # cache-buffer-seconds = "300";
- # prompt-on-shell = true;
- # };
- # };
-
- # ---------------------------------------------------------------------------
- # Step CA - Internal certificate management for local HTTPS
- # See: https://stackpanel.dev/docs/step-ca
- # ---------------------------------------------------------------------------
- # step-ca = {
- # enable = true;
- # ca-url = "https://ca.internal:443";
- # ca-fingerprint = "abc123..."; # Root CA fingerprint for verification
- # provisioner = "admin";
- # cert-name = "dev-workstation";
- # prompt-on-shell = true;
- # };
-
- # ---------------------------------------------------------------------------
- # Secrets - Secrets management configuration
- # See: https://stackpanel.dev/docs/secrets
- # ---------------------------------------------------------------------------
- # secrets = {
- # enable = true;
- # input-directory = ".stack/secrets";
- #
- # # Code generation for type-safe env access
- # codegen = {
- # typescript = {
- # name = "env";
- # directory = "packages/gen/env/src";
- # language = "typescript";
- # };
- # };
- # };
-
- # ---------------------------------------------------------------------------
- # SST - Infrastructure as code configuration
- # See: https://stackpanel.dev/docs/sst
- # ---------------------------------------------------------------------------
- # sst = {
- # enable = true;
- # project-name = "my-project";
- # region = "us-west-2";
- # account-id = "123456789012";
- # config-path = "packages/infra/sst.config.ts";
- #
- # kms = {
- # enable = true;
- # alias = "my-project-secrets";
- # };
- #
- # oidc = {
- # provider = "github-actions";
- # github-actions = {
- # org = "my-org";
- # repo = "*";
- # };
- # };
- # };
-
- # ---------------------------------------------------------------------------
- # Global Services - Shared development services
- # ---------------------------------------------------------------------------
- # globalServices = {
- # enable = true;
- # project-name = "myproject";
- # postgres.enable = true;
- # redis.enable = true;
- # minio.enable = true;
- # };
-
- # ---------------------------------------------------------------------------
- # Caddy - Local HTTPS reverse proxy
- # ---------------------------------------------------------------------------
- # caddy = {
- # enable = true;
- # project-name = "myproject";
- # };
- }
- '';
-
- # ==========================================================================
- # .gitignore boilerplate
- # ==========================================================================
- gitignoreBoilerplate = ''
- # Runtime state (gitignored)
- state/
-
- # Local config overrides (per-user, gitignored)
- config.local.nix
- '';
-
options = {
go_package = "github.com/darkmatter/stackpanel/packages/proto/gen/gopb";
};
diff --git a/nix/stackpanel/devshell/bin.nix b/nix/stackpanel/devshell/bin.nix
index f1a618ef..0ad753ec 100644
--- a/nix/stackpanel/devshell/bin.nix
+++ b/nix/stackpanel/devshell/bin.nix
@@ -86,15 +86,23 @@ in
};
};
- config = lib.mkIf (config.stackpanel.enable && cfg.enable && binDirPaths != [ ]) {
- # Run the bin generator script on shell entry
- stackpanel.devshell.hooks.after = [
- "${generateBinScript}"
- ];
+ config = lib.mkMerge [
+ # Keep .stackpanel/bin out of git — unconditional to avoid a recursion cycle:
+ # the bin-generation mkIf depends on devshell.packages → files → gitignore → cycle.
+ (lib.mkIf (config.stackpanel.enable && cfg.enable) {
+ stackpanel.gitignore.entries = [ ".stackpanel/bin/" ];
+ })
- # Optionally add .stack/bin to PATH
- stackpanel.devshell.path.prepend = lib.mkIf cfg.addToPath [
- "$STACKPANEL_ROOT/.stack/bin"
- ];
- };
+ (lib.mkIf (config.stackpanel.enable && cfg.enable && binDirPaths != [ ]) {
+ # Run the bin generator script on shell entry
+ stackpanel.devshell.hooks.after = [
+ "${generateBinScript}"
+ ];
+
+ # Optionally add .stackpanel/bin to PATH
+ stackpanel.devshell.path.prepend = lib.mkIf cfg.addToPath [
+ "$STACKPANEL_ROOT/.stackpanel/bin"
+ ];
+ })
+ ];
}
diff --git a/nix/stackpanel/modules/bun/module.nix b/nix/stackpanel/modules/bun/module.nix
index e4934805..75b03273 100644
--- a/nix/stackpanel/modules/bun/module.nix
+++ b/nix/stackpanel/modules/bun/module.nix
@@ -402,10 +402,18 @@ in {
# bun2nix CLI: run `bun2nix` after `bun install` to regenerate bun.nix
# whenever bun.lock changes. The postinstall script in the generated
# package.json invokes this automatically.
- stackpanel.devshell.packages = [pkgs.bun2nix];
+ stackpanel.devshell.packages = [
+ pkgs.bun2nix # Native bun2nix CLI (converts bun.lock -> bun.nix)
+ ];
+
+ # -----------------------------------------------------------------------
+ # Devshell - enable the bun language
+ # -----------------------------------------------------------------------
+ stackpanel.languages.javascript.bun.enable = true;
+ stackpanel.languages.javascript.bun.install.enable = true;
# -----------------------------------------------------------------------
- # File Generation — package.json
+ # File Generation - package.json with bun2nix postinstall
# -----------------------------------------------------------------------
# Only generated for apps with generateFiles = true (default). Each entry
# uses json-ops so the file is patched in-place; user-added fields are
diff --git a/packages/docs-content/content/guides/setup.mdx b/packages/docs-content/content/guides/setup.mdx
index 76a9dbde..63007fd3 100644
--- a/packages/docs-content/content/guides/setup.mdx
+++ b/packages/docs-content/content/guides/setup.mdx
@@ -13,7 +13,7 @@ Install the Stackpanel CLI for terminal-based management:
```bash
# Using Nix (recommended)
-nix profile install github:darkmatter/stackpanel
+nix profile install git+ssh://git@github.com/darkmatter/stackpanel
# Using Homebrew
brew install darkmatter/tap/stackpanel