Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-linux-packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
workflow_dispatch:
inputs:
version:
description: 'Package version (e.g., 3.2.1)'
description: 'Package version (e.g., 3.3.0)'
required: false
default: ''

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ These are install paths for [StructKit](https://github.com/httpdss/structkit), n
- [VS Code / Cursor](https://github.com/httpdss/vscode-structkit) — schema and autocomplete for `.structkit.yaml`
- [Agent skills](https://github.com/httpdss/structkit-skills) — inspect, preview, generate, validate from an assistant
- [pre-commit](https://github.com/httpdss/structkit-pre-commit) — validate structures before they land
- [Homebrew](https://github.com/httpdss/homebrew-structkit) — `brew tap httpdss/structkit && brew install structkit`
- [Homebrew](https://github.com/httpdss/homebrew-structkit) — `brew install httpdss/structkit/structkit`
- Linux `.deb` / `.rpm` — download from [build-linux-packages](https://github.com/httpdss/structkit/actions/workflows/build-linux-packages.yaml) workflow artifacts (not attached to GitHub Releases), or build locally per [packaging/README.md](packaging/README.md)
- [Backstage](https://github.com/httpdss/backstage-plugin-structkit) — scaffolder actions for platform teams
- [Hermes plugin](https://github.com/httpdss/hermes-plugin-structkit) — safe StructKit tools inside Hermes

Expand Down Expand Up @@ -82,6 +83,8 @@ Project scaffolding tools exist in most ecosystems, but StructKit solves problem
- **🌐 Remote Content** - Fetch files from GitHub, HTTP/HTTPS, S3, and Google Cloud Storage
- **🛡️ Smart File Handling** - Multiple strategies for managing existing files (overwrite, skip, backup, etc.)
- **🪝 Automation Hooks** - Pre and post-generation shell commands
- **🔒 Hook Safety** - Skip hooks (`--no-hooks` / `STRUCTKIT_NO_HOOKS`), confirm interactively, or restrict commands with an allowlist
- **⚙️ Config Layering** - Merge built-in defaults, `~/.config/struct/config.yaml`, optional `--config-file`, and CLI flags
- **🎯 Dry Run Mode** - Preview changes before applying them
- **✅ Validation & Schema** - Built-in YAML validation and IDE support
- **🤖 MCP Integration** - Model Context Protocol support for AI-assisted development workflows
Expand Down Expand Up @@ -143,6 +146,7 @@ Our comprehensive documentation is organized into the following sections:
- **[YAML Configuration](docs/configuration.md)** - Complete configuration reference
- **[Template Variables](docs/template-variables.md)** - Dynamic content and Jinja2 features
- **[File Handling](docs/file-handling.md)** - Managing files, permissions, and remote content
- **[Environment Variables](docs/environment-variables.md)** - `STRUCTKIT_*` defaults and overrides
- **[Schema Reference](docs/schema.md)** - YAML validation and IDE support

### 🔧 Advanced Features
Expand Down
14 changes: 9 additions & 5 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ These options are available for all commands:

The following environment variables can be used to configure default values for CLI arguments:

- `STRUCTKIT_LOG_LEVEL`: Set the default logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL). Overridden by the `--log` flag.
- `STRUCTKIT_LOG_LEVEL`: Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL). Applied after argument parsing and **overrides** `--log` and `--debug` when set to a non-empty value.
- `STRUCTKIT_STRUCTURES_PATH`: Set the default path to structure definitions. This is used as the default value for the `--structures-path` flag when not explicitly provided. When set, the CLI will log an info message indicating that this environment variable is being used.
- `STRUCTKIT_SOURCES_CONFIG`: Override the user-level named sources config file (default: `$XDG_CONFIG_HOME/structkit/sources.yaml` or `~/.config/structkit/sources.yaml`).
- `STRUCTKIT_SOURCES_CONFIG`: Override the user-level named sources config file (default: `$XDG_CONFIG_HOME/structkit/sources.yaml` or `~/.config/structkit/sources.yaml`). This is separate from the CLI user config at `~/.config/struct/config.yaml`.
- `STRUCTKIT_SOURCES_CACHE`: Override the local cache directory used for git-backed sources (default: `$XDG_CACHE_HOME/structkit/sources` or `~/.cache/structkit/sources`).

See [Environment Variables](environment-variables.md) for the full `STRUCTKIT_*` list (hooks, HTTP, and other flags).

**Precedence:**

1. Explicit `--structures-path` CLI flag (highest priority)
Expand Down Expand Up @@ -121,7 +123,7 @@ Generate the project structure.
**Usage:**

```sh
structkit generate [-h] [-l LOG] [-c CONFIG_FILE] [-i LOG_FILE] [-s STRUCTURES_PATH] [-n INPUT_STORE] [-d] [--diff] [-v VARS] [-b BACKUP] [-f {overwrite,skip,append,rename,backup}] [-p GLOBAL_SYSTEM_PROMPT] [--non-interactive] [--mappings-file MAPPINGS_FILE] [-o {console,file}] [structure_definition] [base_path]
structkit generate [-h] [-l LOG] [-c CONFIG_FILE] [-i LOG_FILE] [-s STRUCTURES_PATH] [-n INPUT_STORE] [-d] [--diff] [-v VARS] [-b BACKUP] [-f {overwrite,skip,append,rename,backup}] [-p GLOBAL_SYSTEM_PROMPT] [--non-interactive] [--mappings-file MAPPINGS_FILE] [-o {console,file}] [--no-hooks] [--hooks-allowlist HOOKS_ALLOWLIST] [structure_definition] [base_path]
```

Defaults when omitted:
Expand Down Expand Up @@ -149,6 +151,8 @@ structkit generate
- `--non-interactive`: Run the command in non-interactive mode.
- `--mappings-file MAPPINGS_FILE`: Path to a YAML file containing mappings to be used in templates (can be specified multiple times).
- `-o {console,file}, --output {console,file}`: Output mode.
- `--no-hooks`: Skip all pre/post hooks. Can be set via `STRUCTKIT_NO_HOOKS` (`true`, `1`, or `yes`).
- `--hooks-allowlist HOOKS_ALLOWLIST`: Path to a hooks allowlist file. Can be set via `STRUCTKIT_HOOKS_ALLOWLIST`. If omitted, `generate` still loads `.struct-hooks-allowlist` in the current directory when that file exists.


### `explain`
Expand Down Expand Up @@ -332,8 +336,8 @@ structkit config print [--format {yaml,json}] [-c CONFIG_FILE]
The `config print` command shows the final merged configuration from all layers:

1. Built-in defaults (lowest priority)
2. User config (`~/.config/struct/config.yaml`)
3. Project config (`.structkit.yaml`, legacy `.struct.yaml`, or `--config-file`)
2. User config (`~/.config/struct/config.yaml`), loaded automatically when present
3. Project config from `--config-file` only (`.structkit.yaml` is not auto-loaded as CLI config)
4. CLI arguments (highest priority)

The command also displays which configuration sources were loaded.
Expand Down
44 changes: 33 additions & 11 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,29 @@

## Config Layering

Structkit supports a layered configuration system that allows you to set defaults at multiple levels. Configuration values are merged in the following order (from lowest to highest priority):
StructKit supports a layered configuration system for **CLI defaults** (file strategy, log level, structures path, and similar flags). Values are merged in this order (lowest to highest priority), matching `load_layered_config` and `main.py`:

1. **Built-in defaults** - Hard-coded defaults that are always present
2. **User config** - Global defaults from `~/.config/struct/config.yaml`
3. **Project config** - Project-specific config from `.structkit.yaml` (legacy `.struct.yaml`) or `--config-file`
4. **CLI arguments** - Command-line flags (highest priority)
1. **Built-in defaults** — Hard-coded defaults that are always present
2. **User config** — `~/.config/struct/config.yaml`, loaded automatically when the file exists
3. **Project config** — Only the file passed with `--config-file` (not auto-loaded)
4. **CLI arguments** — Command-line flags (highest priority)

`.structkit.yaml` (and legacy `.struct.yaml`) is the **structure definition** used by `structkit generate`, `validate`, and similar commands. It is **not** auto-loaded as layered CLI config. To apply project-specific CLI defaults, pass a file with `--config-file`.

Several flags also read `STRUCTKIT_*` environment variables as argparse defaults. Those values are treated like CLI arguments (they override config files) unless you pass a different flag. `STRUCTKIT_LOG_LEVEL` is applied after parsing and overrides `--log` and `--debug`. See [Environment Variables](environment-variables.md).

### User config vs named sources

These are two different files in different directories:

| File | Purpose |
| --- | --- |
| `~/.config/struct/config.yaml` | User-level CLI defaults (`file_strategy`, `log`, `input_store`, and the other options listed below). Loaded automatically when present. The path is `~/.config/struct/config.yaml` as implemented in code (not XDG-overridable). |
| `$XDG_CONFIG_HOME/structkit/sources.yaml` or `~/.config/structkit/sources.yaml` | Named structure sources for `structkit sources`. Override the path with `STRUCTKIT_SOURCES_CONFIG`. See [Custom Structures](custom-structures.md). |

### User Config

You can create a user-level config file at `~/.config/struct/config.yaml` to set your personal defaults. This is useful for setting preferences that apply across all your projects.
Create a user-level config file at `~/.config/struct/config.yaml` to set personal CLI defaults across projects.

Example `~/.config/struct/config.yaml`:

Expand All @@ -24,7 +37,14 @@ log: WARNING

### Project Config

Project-specific settings can be defined in a `.structkit.yaml` file or specified via the `--config-file` flag. These settings override user config and built-in defaults. A legacy `.struct.yaml` file is still accepted when `.structkit.yaml` is not present.
Project-specific CLI defaults are applied only when you pass `--config-file`. There is no automatic lookup of `.structkit.yaml` or `.struct.yaml` for this layer.

```bash
structkit generate --config-file project-config.yaml
structkit config print -c project-config.yaml
```

These settings override user config and built-in defaults. CLI flags still win.

### CLI Arguments

Expand Down Expand Up @@ -80,10 +100,12 @@ The command also displays which configuration sources were used:
Configuration sources:
1. Built-in defaults: always loaded
2. User config: /home/user/.config/struct/config.yaml (exists)
3. Project config: .structkit.yaml
3. Project config: none specified
4. CLI arguments: highest priority
```

When `--config-file` is set, line 3 shows that path instead of `none specified`.

## YAML Configuration Properties

When defining your project structure in the YAML configuration file, you can use various properties to control the behavior of the script. Here are the available properties:
Expand Down Expand Up @@ -197,16 +219,16 @@ latest_release(repo_name: str, strip_v: bool = False, return_sha: bool = False)
| `strip_v` | `bool` | `false` | In version mode, remove exactly one leading lowercase `v` from the release tag. Tags without that prefix, including an uppercase `V`, are unchanged. |
| `return_sha` | `bool` | `false` | Return the commit SHA identified by the release tag instead of the tag name. |

Both options are optional, so existing calls keep their original behavior. For a latest release tagged `v3.2.1`, these examples produce:
Both options are optional, so existing calls keep their original behavior. For a latest release tagged `v3.3.0`, these examples produce:

```yaml
files:
- release.txt:
content: |
# v3.2.1 (unchanged default output)
# v3.3.0 (unchanged default output)
{{@ "httpdss/structkit" | latest_release @}}

# 3.2.1 (strip one leading lowercase "v")
# 3.3.0 (strip one leading lowercase "v")
{{@ "httpdss/structkit" | latest_release(strip_v=true) @}}

# 0123456789abcdef0123456789abcdef01234567 (release commit)
Expand Down
126 changes: 117 additions & 9 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ structkit generate my-custom-structure ./output

Sets the logging level for all commands.

**CLI Equivalent:** `--log` (generate command)
**CLI Equivalent:** Applied in `main.py` after parsing. When set to a non-empty value, it **overrides** `--log` and `--debug`.

**Valid Values:** `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
**Valid Values:** `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` (case-insensitive; unknown values fall back to `INFO`)

**Default:** `INFO`
**Default:** unset, then `--debug` if present, otherwise `--log` (default `INFO`)

**Use Case:** Control verbosity of output for debugging or production deployments.

Expand All @@ -143,14 +143,118 @@ export STRUCTKIT_LOG_LEVEL="DEBUG"
structkit generate my-structure ./output
```

## Hook Safety

### `STRUCTKIT_NO_HOOKS`

Skip all pre-generation and post-generation hooks.

**CLI Equivalent:** `--no-hooks`

**Valid Values:** `true`, `1`, `yes` (case-insensitive) enable skipping; any other value (including unset) leaves hooks enabled

**Default:** unset / false (hooks run, subject to confirmation and allowlist)

**Example:**
```bash
export STRUCTKIT_NO_HOOKS=true
structkit generate my-structure ./output
```

### `STRUCTKIT_HOOKS_ALLOWLIST`

Path to a hooks allowlist file. When hooks are enabled and this is unset, `generate` still loads `.struct-hooks-allowlist` from the current working directory if that file exists.

**CLI Equivalent:** `--hooks-allowlist`

**Default:** unset (`None`); then `.struct-hooks-allowlist` in the current directory if present

**Example:**
```bash
export STRUCTKIT_HOOKS_ALLOWLIST=/path/to/allowlist.txt
structkit generate my-structure ./output
```

## Network and HTTP

Used by GitHub raw-content fetching in `ContentFetcher` (prefer `raw.githubusercontent.com`, then git fallback).

### `STRUCTKIT_DENY_NETWORK`

Skip HTTP attempts and use the git fallback directly. Only the string `1` enables this; `true`/`yes` are **not** recognized.

**Default:** unset (HTTP is attempted)

**Example:**
```bash
export STRUCTKIT_DENY_NETWORK=1
structkit generate my-structure ./output
```

### `STRUCTKIT_HTTP_TIMEOUT`

HTTP timeout in seconds for raw GitHub fetches.

**Default:** `10`

**Example:**
```bash
export STRUCTKIT_HTTP_TIMEOUT=30
```

### `STRUCTKIT_HTTP_RETRIES`

Number of retries after the first HTTP attempt (total attempts = retries + 1).

**Default:** `2`

**Example:**
```bash
export STRUCTKIT_HTTP_RETRIES=0
```

## Named Sources

These configure the **sources** file and git cache. They are separate from the CLI user config at `~/.config/struct/config.yaml`.

### `STRUCTKIT_SOURCES_CONFIG`

Override the user-level named sources config path.

**CLI Equivalent:** `structkit sources --config-path`

**Default:** `$XDG_CONFIG_HOME/structkit/sources.yaml` if `XDG_CONFIG_HOME` is set, otherwise `~/.config/structkit/sources.yaml`

**Example:**
```bash
export STRUCTKIT_SOURCES_CONFIG=~/team/structkit-sources.yaml
structkit sources list
```

### `STRUCTKIT_SOURCES_CACHE`

Override the local cache directory used for git-backed sources.

**Default:** `$XDG_CACHE_HOME/structkit/sources` if `XDG_CACHE_HOME` is set, otherwise `~/.cache/structkit/sources`

**Example:**
```bash
export STRUCTKIT_SOURCES_CACHE=~/cache/structkit-sources
```

## Precedence Rules

Command-line arguments **always take precedence** over environment variables. This allows environment variables to set sensible defaults while maintaining the ability to override them when needed.
For flags that use environment variables as argparse defaults (`STRUCTKIT_STRUCTURES_PATH`, `STRUCTKIT_FILE_STRATEGY`, `STRUCTKIT_INPUT_STORE`, `STRUCTKIT_BACKUP_PATH`, `STRUCTKIT_GLOBAL_SYSTEM_PROMPT`, `STRUCTKIT_NON_INTERACTIVE`, `STRUCTKIT_OUTPUT_MODE`, `STRUCTKIT_NO_HOOKS`, `STRUCTKIT_HOOKS_ALLOWLIST`):

1. Explicit command-line flags
2. Environment variable (argparse default)
3. Layered config files (`--config-file`, then `~/.config/struct/config.yaml`, then built-in defaults)

**Precedence Order (highest to lowest):**
1. Command-line arguments
2. Environment variables
3. Built-in defaults
Because those env vars populate argparse defaults, they override values from config files unless you pass a different CLI flag.

**Exception:** `STRUCTKIT_LOG_LEVEL` is applied after parsing and overrides `--log` and `--debug` when set.

`STRUCTKIT_DENY_NETWORK`, `STRUCTKIT_HTTP_TIMEOUT`, `STRUCTKIT_HTTP_RETRIES`, `STRUCTKIT_SOURCES_CONFIG`, and `STRUCTKIT_SOURCES_CACHE` are read directly where they are used; they are not CLI-config layers.

**Example:**
```bash
Expand All @@ -166,6 +270,8 @@ structkit generate my-structure ./output
# Uses 'backup' from STRUCTKIT_FILE_STRATEGY
```

Layered CLI config (`~/.config/struct/config.yaml` and `--config-file`) sits below those argparse env-var defaults. See [Configuration](configuration.md).

## Docker and Containerization

Environment variables are particularly useful when running StructKit in containers:
Expand Down Expand Up @@ -301,8 +407,10 @@ This should not happen - CLI arguments always take precedence. If you're experie

### Boolean environment variables not working correctly

For `STRUCTKIT_NON_INTERACTIVE`, only `true`, `1`, and `yes` (case-insensitive, e.g., `"True"`, `"TRUE"`, `"YeS"`) are recognized as true values. All other values are treated as false, including:
For `STRUCTKIT_NON_INTERACTIVE` and `STRUCTKIT_NO_HOOKS`, only `true`, `1`, and `yes` (case-insensitive, e.g., `"True"`, `"TRUE"`, `"YeS"`) are recognized as true values. All other values are treated as false, including:
- `"true "` (with trailing space)
- `"on"` or `"enable"`

`STRUCTKIT_DENY_NETWORK` is stricter: only the exact value `1` disables HTTP fetches.

Use one of the recognized values for reliable behavior.
38 changes: 38 additions & 0 deletions docs/github-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,44 @@ jobs:

When `struct_file` is omitted, the workflow uses `.structkit.yaml` if present and falls back to a legacy `.struct.yaml`.

## GitHub Action step (`httpdss/structkit-action`)

For validate, generate, or a dry-run diff/drift check **as a step** in your own job (instead of calling the reusable workflow as a complete job), use [`httpdss/structkit-action`](https://github.com/httpdss/structkit-action).

Validate:

```yaml
- uses: actions/checkout@v7
- uses: httpdss/structkit-action@v1
with:
command: validate
struct_file: .structkit.yaml
```

Drift check (`generate` + `--dry-run --diff`):

```yaml
- uses: httpdss/structkit-action@v1
with:
command: generate
struct_file: .structkit.yaml
dry_run: true
diff: true
fail_on_diff: true
```

Generate:

```yaml
- uses: httpdss/structkit-action@v1
with:
command: generate
struct_file: .structkit.yaml
output_dir: .
```

The reusable workflow above is a full job with built-in PR creation. The action is a step you can mix with other checkout, test, or commit steps. See the [action README](https://github.com/httpdss/structkit-action) for full workflow examples and inputs.

## Best Practices

1. **Secure Your Token**: Store GitHub tokens in secrets management tools.
Expand Down
Loading
Loading