# act — Administrator & Developer Guide

## 1. Architecture Overview

act is a Go CLI that reads GitHub Actions workflow files (`.github/workflows/*.yml`), parses them into an execution plan of stages and jobs, and runs each job inside a Docker container configured to emulate GitHub's hosted runner environment. The tool reproduces environment variables, filesystem layout, event payloads, matrix fan-out, secret masking, and action resolution — all driven from a single binary with zero external dependencies beyond Docker.

### How It Works

```text
CLI (cmd/root.go)
  ├── Workflow Parser (pkg/model/)
  │     ├── planner.go  — reads YAML, builds Plan of Stages/Runs
  │     ├── workflow.go — Job, Step, Strategy, Matrix deserialization
  │     └── action.go   — action.yml parsing (node/docker/composite)
  │
  ├── Runner Engine (pkg/runner/)
  │     ├── runner.go         — NewPlanExecutor, concurrent stage dispatch
  │     ├── job_executor.go   — single job lifecycle (setup → steps → post)
  │     ├── run_context.go    — job-level state (env, secrets, contexts)
  │     ├── step_run.go       — `run:` steps (shell commands)
  │     ├── step_action_local.go  — `uses: ./path` local actions
  │     ├── step_action_remote.go — `uses: owner/repo@ref` remote actions
  │     ├── step_docker.go    — `uses: docker://` steps
  │     ├── action_composite.go   — composite action expansion
  │     ├── expression.go     — ${{ }} expression evaluation
  │     └── reusable_workflow.go  — workflow_call support
  │
  ├── Container Layer (pkg/container/)
  │     ├── docker_run.go     — container lifecycle (create/start/exec/remove)
  │     ├── docker_pull.go    — image pulling with auth
  │     ├── docker_build.go   — local Dockerfile builds
  │     ├── docker_network.go — network create/remove
  │     ├── host_environment.go — host-mode execution (no container)
  │     └── docker_socket.go  — socket discovery and validation
  │
  ├── Services
  │     ├── Artifact Server (pkg/artifacts/)   — v1 + v4 HTTP endpoints
  │     ├── Cache Server (pkg/artifactcache/)  — GitHub Actions cache API
  │     └── Expression Parser (pkg/exprparser/) — GitHub expression language
  │
  └── Utilities
        ├── pkg/common/       — executor framework, logging, auth tokens
        ├── pkg/model/        — GitHub context, planner, workflow types
        ├── pkg/filecollector/ — tar/copy with gitignore support
        ├── pkg/workflowpattern/ — glob pattern matching for triggers
        ├── pkg/schema/       — JSON Schema validation for workflows
        ├── pkg/lookpath/     — cross-platform executable lookup
        └── pkg/gh/           — GitHub CLI token retrieval
```

### Component Inventory

| Component | Path | Role |
|---|---|---|
| CLI entry point | `main.go` → `cmd/root.go` | Cobra command setup, flag parsing, `.actrc` loading |
| Workflow model | `pkg/model/` | YAML parsing, planning, job/step type system |
| Runner engine | `pkg/runner/` | Job execution, step dispatch, expression evaluation |
| Container layer | `pkg/container/` | Docker API interactions, host env fallback |
| Artifact server | `pkg/artifacts/` | Local HTTP server emulating GitHub Artifacts API |
| Cache server | `pkg/artifactcache/` | Local HTTP server emulating GitHub Actions Cache API |
| Expression parser | `pkg/exprparser/` | `${{ }}` expression interpreter |
| Schema validator | `pkg/schema/` | JSON Schema validation for workflow/action YAML |
| File collector | `pkg/filecollector/` | Tar archive creation with `.gitignore` support |
| Workflow patterns | `pkg/workflowpattern/` | Path filter pattern matching |

### Technology Stack

| Layer | Technology |
|---|---|
| Language | Go 1.25 |
| CLI framework | `spf13/cobra` + `spf13/pflag` |
| Docker client | `moby/moby/client` |
| Git operations | `go-git/go-git/v5` |
| YAML parsing | `gopkg.in/yaml.v3` |
| Logging | `sirupsen/logrus` |
| Schema validation | `rhysd/actionlint` + `xeipuuv/gojsonschema` |
| Interactive prompts | `AlecAivazis/survey/v2` |
| Persistent cache DB | `go.etcd.io/bbolt` via `timshannon/bolthold` |
| Protobuf (artifacts v4) | `google.golang.org/protobuf` |

> [!NOTE]
> act uses the Docker Engine API directly — it does not shell out to the `docker` CLI. This means Docker Desktop, Colima, Podman (with Docker-compatible socket), or any Docker API-compatible daemon works.

### Data Flow: Workflow Execution

```text
1. CLI parses args + .actrc → Input struct
2. WorkflowPlanner reads .github/workflows/*.yml → Plan (Stages → Runs)
3. Runner.NewPlanExecutor dispatches Stages sequentially
4. Each Stage runs its Runs (jobs) concurrently (up to --concurrent-jobs)
5. JobExecutor for each Run:
   a. Creates Docker container with platform image
   b. Copies workspace (or bind-mounts)
   c. Resolves and caches actions
   d. Executes steps: run → shell exec, uses → action dispatch
   e. Evaluates ${{ }} expressions, if conditions
   f. Collects outputs, manages step results
   g. Runs post-steps in reverse order
   h. Removes container (unless --reuse)
6. Artifact/Cache servers handle uploads/downloads during execution
```

## 2. System Requirements

| Component | Requirement |
|---|---|
| Docker Engine | v17.09+ (API v1.25+), v20.10+ recommended |
| Docker API | v1.41+ required for `--container-architecture` |
| Go (build only) | 1.25+ |
| Git | Required for repository operations |
| Operating System | Linux, macOS, Windows (WSL2 recommended) |
| Platform support | linux/amd64 (native), linux/arm64, others via QEMU |

> [!IMPORTANT]
> On Windows, act requires WSL2 or Docker Desktop with WSL2 backend. Native Windows containers are not supported. The Docker socket location varies by platform — see Docker Socket Discovery below.

## 3. Configuration Reference

### CLI Flags — Complete Reference

#### Operational Flags

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `[event]` | | positional | `push` | Event name to trigger. Falls back to `push`; if workflow handles only one event, uses that |
| `--job` | `-j` | string | | Run a specific job by ID |
| `--watch` | `-w` | bool | `false` | Watch working directory and re-run on file changes |
| `--list` | `-l` | bool | `false` | List workflows (tabular: Stage, Job ID, Job name, Workflow, File, Events) |
| `--graph` | `-g` | bool | `false` | Draw ASCII workflow dependency graph |
| `--validate` | | bool | `false` | Validate workflow YAML without running |
| `--strict` | | bool | `false` | Enable strict schema validation |
| `--dryrun` | `-n` | bool | `false` | Validate workflows without creating containers |
| `--detect-event` | | bool | `false` | Auto-detect event type from the first workflow |

#### Container Configuration

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--platform` | `-P` | string[] | | Map runner labels to Docker images (e.g., `-P ubuntu-latest=image:tag`) |
| `--container-architecture` | | string | host arch | OS/architecture for containers (e.g., `linux/amd64`) |
| `--container-daemon-socket` | | string | auto-detect | Docker daemon socket URI (e.g., `unix://~/.docker/run/docker.sock`, or `-` to disable mount) |
| `--container-options` | | string | | Extra `docker run` options passed to job containers |
| `--container-cap-add` | | string[] | | Kernel capabilities to add (e.g., `SYS_PTRACE`). **Deprecated** — use `--container-options --cap-add=SYS_PTRACE` |
| `--container-cap-drop` | | string[] | | Kernel capabilities to remove. **Deprecated** — use `--container-options` |
| `--privileged` | | bool | `false` | Run containers in privileged mode. **Deprecated** — use `--container-options --privileged` |
| `--userns` | | string | | User namespace mode. **Deprecated** — use `--container-options` |
| `--network` | | string | `host` | Docker network name for job containers |
| `--reuse` | `-r` | bool | `false` | Keep containers after successful runs |
| `--rm` | | bool | `false` | Auto-remove containers/volumes on workflow failure |
| `--bind` | `-b` | bool | `false` | Bind-mount working directory instead of copying |
| `--pull` | `-p` | bool | `true` | Pull Docker images even if present locally |
| `--rebuild` | | bool | `true` | Rebuild local Docker action images even if present |

> [!WARNING]
> `--privileged`, `--userns`, `--container-cap-add`, and `--container-cap-drop` are deprecated. Use `--container-options` with Docker CLI syntax instead. These flags will be removed in a future version.

#### Secrets, Env, Variables, and Inputs

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--secret` | `-s` | string[] | | Secret with optional value (e.g., `-s NAME=value` or `-s NAME`) |
| `--secret-file` | | string | `.secrets` | Path to secrets file (dotenv or YAML) |
| `--env` | | string[] | | Environment variable with optional value |
| `--env-file` | | string | `.env` | Path to environment file (dotenv or YAML) |
| `--var` | | string[] | | Variable with optional value |
| `--var-file` | | string | `.vars` | Path to variables file |
| `--input` | | string[] | | Action input (e.g., `--input name=value`) |
| `--input-file` | | string | `.input` | Path to inputs file |
| `--insecure-secrets` | | bool | `false` | Print secrets in logs (not recommended) |

#### Path and Workflow Configuration

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--directory` | `-C` | string | `.` | Working directory |
| `--workflows` | `-W` | string | `./.github/workflows/` | Path to workflow files |
| `--no-recurse` | | bool | `false` | Don't search workflow subdirectories |
| `--eventpath` | `-e` | string | | Path to event JSON file |
| `--defaultbranch` | | string | auto-detect | Main branch name |
| `--remote-name` | | string | `origin` | Git remote name for repo URL detection |

#### Actor and GitHub Instance

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--actor` | `-a` | string | `nektos/act` | User that triggered the event |
| `--github-instance` | | string | `github.com` | GitHub instance (for GHE) |
| `--replace-ghe-action-with-github-com` | | string[] | | GHE actions to redirect to github.com |
| `--replace-ghe-action-token-with-github-com` | | string | | PAT for private github.com actions (used with above) |

#### Artifact Server

| Flag | Type | Default | Description |
|---|---|---|---|
| `--artifact-server-path` | string | (disabled) | Storage directory. Server only starts if set |
| `--artifact-server-addr` | string | outbound IP | Bind address |
| `--artifact-server-port` | string | `34567` | Listen port |

#### Cache Server

| Flag | Type | Default | Description |
|---|---|---|---|
| `--no-cache-server` | bool | `false` | Disable the built-in cache server |
| `--cache-server-path` | string | `~/.cache/actcache` | Cache storage directory |
| `--cache-server-addr` | string | outbound IP | Bind address |
| `--cache-server-port` | uint16 | `0` (random) | Listen port |
| `--cache-server-external-url` | string | | External URL if behind a proxy |

#### Action Cache

| Flag | Type | Default | Description |
|---|---|---|---|
| `--action-cache-path` | string | `~/.cache/act` | Directory for cached actions and host workspaces |
| `--action-offline-mode` | bool | `false` | Use cached actions without fetching. Disables `--pull` |
| `--use-new-action-cache` | bool | `false` | Enable Go-git-based action cache |
| `--local-repository` | string[] | | Map remote action refs to local paths |

#### Output and Logging

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--verbose` | `-v` | bool | `false` | Debug-level output |
| `--quiet` | `-q` | bool | `false` | Suppress step output |
| `--json` | | bool | `false` | JSON-formatted log output |
| `--log-prefix-job-id` | | bool | `false` | Use job ID instead of full name in log prefix |

#### Execution Control

| Flag | Type | Default | Description |
|---|---|---|---|
| `--matrix` | string[] | | Filter matrix combinations (e.g., `--matrix os:ubuntu-latest`) |
| `--no-skip-checkout` | bool | `false` | Run `actions/checkout` instead of local file copy |
| `--use-gitignore` | bool | `true` | Exclude `.gitignore` paths from container copy |
| `--concurrent-jobs` | int | num CPUs | Maximum concurrent jobs |

#### Utility Flags

| Flag | Type | Description |
|---|---|---|
| `--bug-report` | bool | Print system info for bug reports |
| `--man-page` | bool | Print generated man page to stdout |
| `--list-options` | bool | Print flags as JSON |
| `--version` | bool | Print version |
| `--help` | bool | Print help |

### Environment Variables

| Variable | Purpose |
|---|---|
| `DOCKER_HOST` | Docker daemon URI (overridden by `--container-daemon-socket`) |
| `ACT_DISABLE_VERSION_CHECK` | Set to `1` to suppress startup version notices |
| `XDG_CACHE_HOME` | Override cache base directory (default: `~/.cache`) |
| `CLICOLOR` | Controls colored output in graph drawing |
| `NORAW` | Disables raw terminal mode for Docker attach |

> [!TIP]
> Variables `ACT_ACTOR`, `ACT_REPOSITORY`, and `ACT_OWNER` are used in tests to override the actor, repository, and owner. They are not part of the normal user-facing API.

### Configuration File Format

The `.actrc` file is a line-per-flag format with environment variable expansion:

```text
# Comments are not supported — every non-empty line is treated as an argument
-P ubuntu-latest=catthehacker/ubuntu:act-latest
-P ubuntu-22.04=catthehacker/ubuntu:act-22.04
--container-architecture linux/amd64
--artifact-server-path ${HOME}/.act-artifacts
--action-offline-mode
```

Lines starting with `-` are split at the first whitespace to separate flag from value. Lines without `-` prefix are ignored when `split=true` (the default for config loading).

## 4. Deployment & Scaling

### Building from Source

```bash
git clone https://github.com/nektos/act.git
cd act
go build -o act .
```

```text
# Verify
./act --version
```

The `VERSION` file at the repository root is embedded at compile time via `//go:embed`.

### GoReleaser Configuration

act uses GoReleaser (`.goreleaser.yml`) for cross-platform release builds. Release artifacts include binaries for Linux, macOS, and Windows across amd64/arm64, plus a Chocolatey NuGet package (`act-cli.nuspec`).

### Docker Socket Discovery

act searches for the Docker socket in a platform-specific order:

1. `DOCKER_HOST` environment variable (if set)
2. `--container-daemon-socket` flag (if provided)
3. Common socket locations checked in order:
   - `/var/run/docker.sock`
   - `/run/podman/podman.sock`
   - `$HOME/.docker/run/docker.sock`
   - `$HOME/.colima/default/docker.sock`
   - `$XDG_RUNTIME_DIR/docker.sock`
   - `$XDG_RUNTIME_DIR/podman/podman.sock`
   - `\\.\pipe\docker_engine` (Windows)

> [!NOTE]
> If `--container-daemon-socket` is set to `-`, act will not bind-mount the Docker socket into job containers. This is useful for security-sensitive environments where container-in-container access should be prevented.

### Scaling Considerations

- **Concurrent jobs**: Controlled by `--concurrent-jobs`. Defaults to CPU count. Each job creates its own container.
- **Disk usage**: Each job copies the workspace into the container (unless `--bind` is used). Large repos multiply disk usage by job count.
- **Network**: The `host` network mode (default) shares the host network stack. Named networks provide isolation but require address configuration for artifact/cache servers.
- **Cache server**: Uses BoltDB (`bbolt`) for metadata and filesystem for blobs. Not designed for multi-process concurrent access.

## 5. Operations

### Cache Management

**Action cache** (`~/.cache/act/` by default):

- Stores cloned action repositories (bare git repos when using `--use-new-action-cache`)
- Host workspaces for jobs
- Clean with: `rm -rf ~/.cache/act/`

**Artifact cache** (`~/.cache/actcache/` by default):

- BoltDB database + artifact blob files
- Stores GitHub Actions cache entries (keys, versions, content)
- Clean with: `rm -rf ~/.cache/actcache/`

> [!TIP]
> The cache server supports garbage collection internally. Caches that haven't been accessed are candidates for removal based on the BoltDB `Complete` and `UsedAt` timestamps.

### Monitoring Execution

Use `--verbose` (`-v`) for debug-level logs showing:

- Docker API calls (pull, create, start, exec)
- Expression evaluation results
- Action resolution and caching decisions
- Environment variable loading

Use `--json` for structured log output parseable by tools like `jq`:

```bash
act --json 2>&1 | jq 'select(.msg | contains("Run Main"))'
```

> [!NOTE]
> Log output goes to stderr. Step output (the actual command outputs) goes to stdout. Use `--quiet` to suppress step output.

### Version Notices

act checks `https://api.nektosact.com/notices` on each run (unless `ACT_DISABLE_VERSION_CHECK=1`). The check uses HTTP conditional GET (ETag caching) to minimize bandwidth. Notices are displayed after the workflow run with a 1-second timeout — they never block execution.

## 6. Performance

### Image Pull Optimization

- Default: `--pull=true` — always pulls images (ensures latest version)
- Fast iteration: `--pull=false` — uses local image if available
- Offline: `--action-offline-mode` — no network at all

### Workspace Copy vs Bind

| Mode | Flag | Speed | Safety |
|---|---|---|---|
| Copy (default) | none | Slower start, full isolation | Workflows cannot modify host files |
| Bind mount | `--bind` / `-b` | Instant start | Workflows can modify host files |

### Action Caching

Two cache implementations:

| Cache | Flag | Method | Best for |
|---|---|---|---|
| Default | none | `git clone` via shell | Reliability |
| Go-git | `--use-new-action-cache` | In-process bare git + go-git | Speed, offline mode |

The Go-git cache resolves refs to SHAs, stores bare repos, and extracts files via tree walking — avoiding shell subprocess overhead.

### Offline Mode

`--action-offline-mode` skips all network fetches:

- Docker pull is forced off
- Action cache uses existing clones without fetch
- Requires prior run to populate caches

## 7. Security

### Secret Handling

- Secrets are masked in output by default using pattern matching against the `*[]string` masks context
- `--insecure-secrets` disables masking (logs will show secret values)
- Secrets are case-insensitive (stored as uppercase keys internally)
- Secret values can be provided interactively (terminal password prompt) if not set inline or via environment

> [!CAUTION]
> `--insecure-secrets` should never be used in CI pipelines or shared terminal sessions. Secret values will be visible in all log output.

### Docker Socket Access

By default, act bind-mounts the Docker socket into job containers. This provides Docker-in-Docker capability but gives containers full Docker API access.

- Use `--container-daemon-socket -` to disable socket mounting
- Use `--container-cap-drop` or `--container-options --cap-drop=ALL` to restrict capabilities

### GitHub Token

If no `GITHUB_TOKEN` secret is provided, act attempts to retrieve one from the `gh` CLI by running `gh auth token`. This uses the logged-in user's token.

> [!WARNING]
> Be aware that the auto-detected token may be scoped to a different GitHub instance (e.g., GHE) than expected. Pass tokens explicitly in multi-instance environments. (See GitHub issue [#6077](https://github.com/nektos/act/issues/6077))

### Authorization Tokens (Internal)

The artifact cache server uses JWT tokens for request authorization:

- Tokens are signed with HMAC-SHA256 using a randomly generated key per session
- Token claims include `TaskID`, `RunID`, `JobID`, and `ac` (action cache scope)
- Tokens are validated on every cache API request

### Path Traversal Protection

The artifact server uses `safeResolve()` to prevent path traversal attacks:

```go
func safeResolve(baseDir string, relPath string) string {
    return filepath.Join(baseDir, filepath.Clean(filepath.Join(string(os.PathSeparator), relPath)))
}
```

Symlink resolution in action steps enforces depth limits (`max depth %d of symlinks exceeded`) and boundary checks (`symlink tries to access file outside of`).

### Input Validation

- Workflow YAML is validated against JSON Schema (`pkg/schema/workflow_schema.json`, `pkg/schema/action_schema.json`)
- Expression parser validates function calls against known function signatures with arity checks
- Job names are validated against the regex pattern `[a-zA-Z_][a-zA-Z0-9_-]*`

## 8. Developer Internals

### Repository Structure

```text
act/
├── main.go                  — entry point, embeds VERSION
├── main_test.go             — smoke test
├── Makefile                 — build targets
├── go.mod / go.sum          — Go module definition
├── VERSION                  — version string (embedded at compile)
├── install.sh               — shell installer script
├── .goreleaser.yml          — release automation config
├── .golangci.yml            — linter configuration
├── .actrc                   — default config (project-level)
├── act-cli.nuspec           — Chocolatey package spec
│
├── cmd/                     — CLI layer
│   ├── root.go              — Cobra root command, all flags, run logic
│   ├── input.go             — Input struct (all CLI options)
│   ├── secrets.go           — Secret parsing with interactive prompt
│   ├── platforms.go         — Default platform mapping
│   ├── list.go              — `--list` tabular output
│   ├── graph.go             — `--graph` ASCII art
│   ├── notices.go           — Version notice fetching (nektosact.com)
│   └── dir.go               — Home/cache directory resolution
│
├── pkg/model/               — Workflow data model
│   ├── workflow.go          — Workflow, Job, Step, Strategy, Defaults types
│   ├── action.go            — Action definition (runs.using, inputs, outputs)
│   ├── planner.go           — WorkflowPlanner: read YAML → Plan/Stages/Runs
│   ├── github_context.go    — GitHub context (ref, sha, repository, owner)
│   ├── job_context.go       — Job context type
│   ├── step_result.go       — Step result status enum
│   └── anchors.go           — YAML anchor/alias cycle detection
│
├── pkg/runner/              — Execution engine
│   ├── runner.go            — Runner interface, Config struct, plan executor
│   ├── job_executor.go      — Job lifecycle (container → steps → cleanup)
│   ├── run_context.go       — RunContext: state, env, binds, GitHub context
│   ├── step.go              — Step interface, conditional evaluation
│   ├── step_run.go          — Shell command execution
│   ├── step_action_local.go — Local action dispatch
│   ├── step_action_remote.go— Remote action fetch + dispatch
│   ├── step_docker.go       — docker:// URL action dispatch
│   ├── step_factory.go      — Step type routing
│   ├── action.go            — Action reading (action.yml/yaml/Dockerfile)
│   ├── action_composite.go  — Composite action step expansion
│   ├── action_cache.go      — GoGitActionCache (bare git repos)
│   ├── action_cache_offline_mode.go — Offline cache wrapper
│   ├── local_repository_cache.go   — Local repo override cache
│   ├── expression.go        — Expression evaluator wiring
│   ├── reusable_workflow.go — workflow_call support
│   ├── command.go           — Workflow command processing (set-env, add-path, etc.)
│   └── logger.go            — Job/step logging with secret masking
│
├── pkg/container/           — Docker abstraction layer
│   ├── container_types.go   — NewContainerInput, FileEntry, build/pull inputs
│   ├── docker_run.go        — Container lifecycle (create/start/exec/copy/remove)
│   ├── docker_pull.go       — Image pull with auth
│   ├── docker_build.go      — Dockerfile build executor
│   ├── docker_images.go     — Image existence/removal
│   ├── docker_network.go    — Network create/remove
│   ├── docker_volume.go     — Volume removal
│   ├── docker_auth.go       — Docker registry auth from config
│   ├── docker_cli.go        — Container option parsing (1,135 lines)
│   ├── docker_logger.go     — Docker log message parsing
│   ├── docker_socket.go     — Socket discovery + SocketAndHost
│   ├── docker_stub.go       — Stub implementations (unsupported platforms)
│   ├── host_environment.go  — Host execution mode (no Docker)
│   ├── executions_environment.go — ExecutionsEnvironment interface
│   ├── linux_container_environment_extensions.go — Container path helpers
│   ├── parse_env_file.go    — Environment file parser (GITHUB_ENV format)
│   ├── util.go              — UID/GID detection (Linux)
│   ├── util_windows.go      — Windows UID stub
│   ├── util_openbsd_mips64.go — OpenBSD stub
│   └── util_plan9.go        — Plan9 stub
│
├── pkg/artifacts/           — Artifact server (v1 + v4)
│   ├── server.go            — HTTP routes for upload/download (v1 API)
│   ├── artifacts_v4.go      — Protobuf-based v4 API routes
│   └── artifact.pb.go       — Generated protobuf types
│
├── pkg/artifactcache/       — Cache server
│   ├── handler.go           — HTTP handler, BoltDB storage, JWT auth
│   ├── model.go             — Cache request/response types
│   ├── storage.go           — Blob storage (filesystem)
│   └── doc.go               — Package documentation
│
├── pkg/exprparser/          — Expression language interpreter
│   ├── interpreter.go       — ${{ }} evaluation engine
│   └── functions.go         — Built-in functions (contains, startsWith, hashFiles, etc.)
│
├── pkg/schema/              — Workflow validation
│   ├── schema.go            — JSON Schema validator
│   ├── workflow_schema.json — GitHub Actions workflow schema
│   └── action_schema.json   — GitHub Actions action.yml schema
│
├── pkg/filecollector/       — File collection for container copy
│   └── file_collector.go    — TarCollector, CopyCollector with gitignore
│
├── pkg/workflowpattern/     — Path filter patterns
│   └── workflow_pattern.go  — Glob-style pattern matching for triggers
│
├── pkg/common/              — Shared utilities
│   ├── executor.go          — Executor functional pattern (Pipeline, Parallel, Conditional)
│   ├── context.go           — Graceful cancellation (SIGINT/SIGTERM)
│   ├── logger.go            — Context-scoped logging
│   ├── auth.go              — JWT token generation/validation
│   ├── draw.go              — ASCII box/arrow drawing
│   ├── dryrun.go            — Dry-run context flag
│   ├── file.go              — CopyFile/CopyDir helpers
│   ├── job_error.go         — Job error context
│   ├── line_writer.go       — Line-buffered writer
│   ├── outbound_ip.go       — Outbound IP detection
│   └── cartesian.go         — Cartesian product (matrix expansion)
│
├── pkg/lookpath/            — Cross-platform executable lookup
│   ├── lp_unix.go           — Unix PATH lookup
│   ├── lp_windows.go        — Windows PATH + PATHEXT lookup
│   ├── lp_plan9.go          — Plan9 stub
│   └── lp_js.go             — JS/WASM stub
│
└── pkg/gh/                  — GitHub CLI integration
    └── gh.go                — Token retrieval via `gh auth token`
```

### Architecture Deep Dive

#### Executor Pattern

The core abstraction is `common.Executor` — a function `func(context.Context) error`. All operations (container create, step run, file copy) are executors composed with combinators:

- `NewPipelineExecutor(a, b, c)` — sequential
- `NewParallelExecutor(n, a, b, c)` — concurrent with limit `n`
- `NewConditionalExecutor(cond, ifTrue, ifFalse)` — branching
- `.Then(next)` — chaining
- `.If(cond)` / `.IfNot(cond)` — conditional execution
- `.Finally(cleanup)` — guaranteed cleanup
- `.OnError(handler)` — error handling

This makes the execution pipeline declarative and composable while keeping error propagation clean.

#### Workflow Planning

`WorkflowPlanner` (`pkg/model/planner.go`) reads all YAML files, builds a dependency graph based on `needs:` declarations, and produces a `Plan`:

```go
type Plan struct {
    Stages []*Stage  // Stages run sequentially
}

type Stage struct {
    Runs []*Run      // Runs within a stage run concurrently
}

type Run struct {
    Workflow *Workflow
    JobID    string
}
```

Planning supports filtering by event name (`PlanEvent`), job ID (`PlanJob`), or all jobs (`PlanAll`).

#### Expression Evaluation

The `pkg/exprparser/` package implements the full GitHub Actions expression language:

- **Literals**: `null`, `true`, `false`, numbers, strings
- **Operators**: `==`, `!=`, `&&`, `||`, `!`, `<`, `>`, `<=`, `>=`
- **Contexts**: `github`, `env`, `secrets`, `steps`, `matrix`, `needs`, `inputs`, `vars`, `runner`, `job`
- **Functions**: `contains()`, `startsWith()`, `endsWith()`, `format()`, `join()`, `toJSON()`, `fromJSON()`, `hashFiles()`, `success()`, `failure()`, `cancelled()`, `always()`

The interpreter uses `rhysd/actionlint` for parsing and implements its own evaluation with type coercion matching GitHub's behavior.

#### Container Options Parsing

`pkg/container/docker_cli.go` (1,135 lines) implements a comprehensive Docker CLI option parser that accepts all standard `docker run` flags. This is used when `--container-options` is passed to transform CLI-style flags into Docker API `container.Config` and `container.HostConfig` structs. Supported flags include volumes, ports, devices, memory limits, healthchecks, network config, security options, and more.

#### Action Resolution

Actions are resolved in order:

1. **Local actions** (`uses: ./path`): Read from workspace, follow symlinks (depth-limited)
2. **Remote actions** (`uses: owner/repo@ref`): Clone from GitHub (or cache), extract action.yml
3. **Docker URL** (`uses: docker://image`): Pull and run directly
4. **Composite actions**: Expand steps recursively with isolated run contexts

The action reader looks for `action.yml` → `action.yaml` → `Dockerfile` (synthetic action) → trampoline.js (synthetic node action with `args`).

#### Service Containers

Service containers (`job.services`) are started before the job and connected to the job's Docker network. Health checks are supported — the job waits for services to become healthy before proceeding with steps.

### Module Reference

#### `cmd/root.go` — CLI Entry Point (776 lines)

The central orchestration file. `createRootCommand()` defines all 60+ flags. `newRunCommand()` is the main run handler that:

1. Discovers Docker socket
2. Loads envs, secrets, vars, inputs from files
3. Auto-retrieves `GITHUB_TOKEN` from `gh` CLI
4. Plans workflow execution
5. Configures runner with `Config` struct
6. Starts artifact/cache servers
7. Dispatches execution (or watch mode)

#### `pkg/runner/runner.go` — Runner Engine (226 lines)

Defines `Runner` interface with `NewPlanExecutor()` method. The `runnerImpl` dispatches stages sequentially and jobs within each stage concurrently (up to `ConcurrentJobs`). Failed jobs are reported with `Job '%s' failed` errors.

#### `pkg/runner/run_context.go` — Job State (1,153 lines)

The `RunContext` struct holds all job-level state:

- Container reference and environment
- Step results and outputs
- GitHub context (event, ref, sha, etc.)
- Expression evaluator factory
- Service container management
- Binds and mounts resolution

Key method `Executor()` builds the job lifecycle executor: container setup → step execution → cleanup.

#### `pkg/runner/expression.go` — Expression Wiring (401 lines)

Bridges the runner context with the expression parser. Populates the `EvaluationEnvironment` with all GitHub Actions contexts (`github.*`, `env.*`, `secrets.*`, `steps.*`, `matrix.*`, `needs.*`, `runner.*`, `job.*`, `inputs.*`, `vars.*`).

#### `pkg/container/docker_run.go` — Container Lifecycle (913 lines)

Implements the full Docker container lifecycle:

- `NewContainer()` — creates container reference
- `Create()` — Docker API container creation with config
- `Start()` — starts container with optional attach
- `Exec()` — runs commands inside container
- `Copy()` / `CopyDir()` — file transfer to container
- `Remove()` — cleanup
- `GetDockerClient()` — creates Docker API client from `DOCKER_HOST`

#### `pkg/artifactcache/handler.go` — Cache Server (569 lines)

Implements the GitHub Actions cache API:

- `POST /_apis/artifactcache/cache` — reserve cache entry
- `PATCH /_apis/artifactcache/caches/:id` — upload cache blob
- `POST /_apis/artifactcache/caches/:id` — commit cache
- `GET /_apis/artifactcache/cache` — lookup cache by key/version

Uses BoltDB for metadata storage and filesystem for blob storage. JWT authorization protects all endpoints.

### Code Patterns and Conventions

| Pattern | Usage |
|---|---|
| Executor composition | All side effects wrapped in `common.Executor` functions |
| Context-scoped state | Logger, dry-run flag, job errors stored in `context.Context` |
| Interface-based DI | `ExecutionsEnvironment` interface enables Docker/host/stub swapping |
| Functional options | Executor combinators (`.Then()`, `.If()`, `.Finally()`) |
| Embed directives | `VERSION` file, `trampoline.js`, schema JSON embedded at compile |
| Table-driven tests | All test files use `t.Run()` with test case tables |
| Platform build tags | `util_windows.go`, `util_openbsd_mips64.go`, `lp_unix.go` etc. |

### Testing Strategy

- **Unit tests**: Extensive in every package. Table-driven with `testify/assert`.
- **Integration tests**: `pkg/runner/runner_test.go` (782 lines) runs real workflows against Docker.
- **Test fixtures**: `pkg/runner/testdata/` contains 100+ workflow scenarios covering:
  - Matrix strategies, composite actions, reusable workflows
  - Service containers, environment files, secret handling
  - Docker actions (local, remote, URL), Node.js actions (12/16/20)
  - Shell variants (bash, sh, python, pwsh, cmd)
  - Edge cases (spaces in paths, nested composites, symlinks)
- **Mock containers**: `container_mock_test.go` provides test doubles for the container interface.
- **Linting**: golangci-lint (`.golangci.yml`), codespell (`.codespellrc`), markdownlint, megalinter, prettierrc.

### Potential Improvements

Based on code analysis and community issues:

- **OIDC token support**: Currently unsupported — actions needing `ACTIONS_ID_TOKEN_REQUEST_URL` fail. Would require a local OIDC provider or mock.
- **Job-level `strategy.job-index` / `strategy.job-total`**: Missing from strategy context (GitHub issue [#5976](https://github.com/nektos/act/issues/5976)).
- **Git worktree support**: `.git` file reconstitution for container mounts (GitHub issue [#6074](https://github.com/nektos/act/issues/6074)).
- **Concurrent instance locking**: No coordination between multiple act processes (GitHub issue [#6061](https://github.com/nektos/act/issues/6061)).
- **Network-scoped artifact/cache servers**: When `--network` is not `host`, servers need explicit address configuration (GitHub issue [#5996](https://github.com/nektos/act/issues/5996)).
- **`docker_cli.go` complexity**: At 1,135 lines, the container options parser is a large single file that could benefit from decomposition.

### Contributing

- **Code**: Go 1.25+, run `make` for build, `make test` for tests
- **Linting**: `golangci-lint run` (configuration in `.golangci.yml`)
- **Tests**: Add test workflows in `pkg/runner/testdata/` for new features
- **Schema**: Update `pkg/schema/workflow_schema.json` / `action_schema.json` for new workflow syntax

## 9. Integration Points

### Docker Engine API

act communicates directly with the Docker Engine API via `moby/moby/client`. Required API operations:

- Container: Create, Start, Remove, Exec, Inspect, CopyToContainer
- Image: Pull, Build, List, Remove
- Network: Create, Remove
- Volume: Remove
- System: Info (for bug reports)

### GitHub CLI (`gh`)

act calls `gh auth token` to retrieve the user's GitHub token when no `GITHUB_TOKEN` secret is provided. This is a one-time call wrapped in `common.EarlyCancelContext` with cancellation support.

### Artifact Server Endpoints (Internal)

| Method | Path | Protocol | Purpose |
|---|---|---|---|
| `POST` | `/_apis/pipelines/workflows/:runId/artifacts` | v1 | Create artifact container |
| `PUT` | `/upload/:runId` | v1 | Upload artifact blob |
| `PATCH` | `/_apis/pipelines/workflows/:runId/artifacts` | v1 | Finalize artifact |
| `GET` | `/_apis/pipelines/workflows/:runId/artifacts` | v1 | List artifacts |
| `GET` | `/download/:container` | v1 | Download artifact |
| `GET` | `/artifact/*path` | v1 | Serve artifact file |

v4 endpoints use protobuf-encoded requests at `/twirp/github.actions.results.api.v1.ArtifactService/*`.

### Version Notice API

```text
GET https://api.nektosact.com/notices?os={os}&arch={arch}&version={version}
```

Returns JSON array of `{"level": "info|warning", "message": "..."}`. Supports ETag-based conditional GET.

## 10. Troubleshooting

### Diagnostic Checklist

- [ ] Docker daemon is running (`docker info`)
- [ ] Docker socket is accessible (`ls -la /var/run/docker.sock`)
- [ ] Workflow files exist at the expected path (`act -l`)
- [ ] Required secrets are set (`-s` or `--secret-file`)
- [ ] Platform mapping matches `runs-on` labels (`-P`)
- [ ] Network connectivity for action downloads (or `--action-offline-mode`)
- [ ] Sufficient disk space for runner images

### Error: `cache %d: not reserved`

**Cause:** The cache server received a commit request for a cache ID that was never reserved.

**Solution:** This is typically a race condition in the action. Retry the workflow. If persistent, check that `ACTIONS_CACHE_URL` is accessible from within the container.

> [!WARNING]
> When using custom Docker networks (`--network`), the cache server's auto-detected address may not be reachable from containers. Use `--cache-server-addr` with an address that is routable from the container network.

### Error: `workflow is not valid. '%s': Job name '%s' is invalid`

**Cause:** Job names must start with a letter or `_` and contain only `[a-zA-Z0-9_-]`.

**Solution:** Rename the job in your workflow YAML to use valid characters.

### Error: `Actions YAML Schema Validation Error detected`

**Cause:** Workflow YAML doesn't conform to the GitHub Actions schema.

**Solution:** Visit `https://nektosact.com/usage/schema.html` for details. Use `--validate --strict` for detailed error output.

> [!NOTE]
> Schema validation errors include context paths showing exactly which YAML key failed validation. The `--strict` flag enables additional checks that GitHub might not enforce but represent best practices.

### Error: `unable to determine outbound IP address`

**Cause:** The cache/artifact server couldn't detect the host's outbound IP for binding.

**Solution:** Specify addresses explicitly:
```bash
act --artifact-server-addr 0.0.0.0 --cache-server-addr 0.0.0.0
```

## 11. Reference

### Supported Action Types

| `runs.using` value | Description |
|---|---|
| `node12` | Node.js 12 action |
| `node16` | Node.js 16 action |
| `node20` | Node.js 20 action |
| `docker` | Docker container action |
| `composite` | Composite action (nested steps) |

### Supported Event Types

act supports all GitHub Actions event types. The event name is passed as the first positional argument. Default is `push`. If a workflow handles only one event, that event becomes the default.

### Expression Functions

| Function | Signature | Description |
|---|---|---|
| `contains` | `contains(search, item)` | Case-insensitive string/array search |
| `startsWith` | `startsWith(str, prefix)` | String prefix check |
| `endsWith` | `endsWith(str, suffix)` | String suffix check |
| `format` | `format(fmt, args...)` | String formatting with `{0}` placeholders |
| `join` | `join(array, separator)` | Array to string |
| `toJSON` | `toJSON(value)` | Value to JSON string |
| `fromJSON` | `fromJSON(str)` | JSON string to value |
| `hashFiles` | `hashFiles(patterns...)` | SHA-256 hash of matching files |
| `success` | `success()` | Previous steps all succeeded |
| `failure` | `failure()` | Any previous step failed |
| `cancelled` | `cancelled()` | Workflow was cancelled |
| `always` | `always()` | Always true |

### Workflow Commands Supported

| Command | Syntax | Description |
|---|---|---|
| `set-env` | `::set-env name=NAME::VALUE` | Set environment variable |
| `set-output` | `::set-output name=NAME::VALUE` | Set step output |
| `add-path` | `::add-path::PATH` | Prepend to PATH |
| `add-mask` | `::add-mask::VALUE` | Mask a value in logs |
| `save-state` | `::save-state name=NAME::VALUE` | Save state for post steps |
| `stop-commands` | `::stop-commands::TOKEN` | Pause command processing |
| `debug` | `::debug::MESSAGE` | Debug message |
| `warning` | `::warning::MESSAGE` | Warning annotation |
| `error` | `::error::MESSAGE` | Error annotation |
| `group` | `::group::TITLE` | Begin log group |
| `endgroup` | `::endgroup::` | End log group |

---

_Generated May 2026 from nektos/act at bd86152. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
