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
33 changes: 20 additions & 13 deletions .github/workflows/docs-links.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,36 @@ permissions:
contents: read

jobs:
readme-links:
name: README link check
doc-links:
name: Doc link check (README + docs/**)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Verify relative .md links in README resolve
- name: Verify relative .md links resolve
run: |
python3 - <<'PY'
import re, os, sys
text = open("README.md").read()
targets = ["README.md"]
for root, _, files in os.walk("docs"):
for f in files:
if f.endswith(".md"):
targets.append(os.path.join(root, f))
bad = []
for m in re.finditer(r"\[([^\]]+)\]\(([^)]+\.md)(#[^)]*)?\)", text):
label, target = m.group(1), m.group(2)
if target.startswith("http"):
continue
resolved = os.path.normpath(os.path.join(".", target))
if not os.path.exists(resolved):
bad.append(f" [{label}]({target})")
for path in targets:
with open(path) as fp:
text = fp.read()
for m in re.finditer(r"\[([^\]]+)\]\(([^)]+\.md)(#[^)]*)?\)", text):
label, target = m.group(1), m.group(2)
if target.startswith("http"):
continue
resolved = os.path.normpath(os.path.join(os.path.dirname(path), target))
if not os.path.exists(resolved):
bad.append(f" {path}: [{label}]({target})")
if bad:
print("Broken relative .md links in README.md:")
print("Broken relative .md links:")
for line in bad:
print(line)
sys.exit(1)
print("README.md: all relative .md links resolve")
print(f"Checked {len(targets)} doc files: all relative .md links resolve")
PY
2 changes: 1 addition & 1 deletion docs/core-concepts/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ When channels are configured in `forge.yaml`, the build pipeline automatically:
1. **Includes channel config files** — `slack-config.yaml`, `telegram-config.yaml`, etc. are copied into the Docker build context alongside `forge.yaml`
2. **Adds `--with` to the entrypoint** — The container entrypoint becomes `["forge", "run", "--host", "0.0.0.0", "--with", "slack,telegram"]`
3. **Surfaces channel env vars in the manifests** — Every `_env`-suffixed setting in each `<channel>-config.yaml` (e.g. `bot_token_env: SLACK_BOT_TOKEN`) is unioned into the Kubernetes `secrets.yaml` and `deployment.yaml` (via `secretKeyRef`) and into the docker-compose adapter services. Both outputs derive from the same source — see [Kubernetes — Env Var Injection](../deployment/kubernetes.md#env-var-injection)
4. **Handles auth loopback** — When [external auth](runtime.md#external-authentication) is configured, channel adapters authenticate to the A2A server using an internal token, bypassing the external auth provider
4. **Handles auth loopback** — When [external auth](runtime-engine.md#external-authentication) is configured, channel adapters authenticate to the A2A server using an internal token, bypassing the external auth provider

Pass channel secrets via environment variables:

Expand Down
4 changes: 2 additions & 2 deletions docs/core-concepts/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ hooks.Register(engine.BeforeToolExec, func(ctx context.Context, hctx *engine.Hoo

`AfterToolExec` hooks can modify `hctx.ToolOutput` to redact sensitive content before it enters the LLM context. The agent loop reads back `ToolOutput` from the `HookContext` after all hooks fire.

The runner registers a guardrail hook that scans tool output for secrets and PII patterns. The hook passes `hctx.ToolName` to the guardrail engine, enabling per-tool exemptions via `allow_tools` config. See [Tool Output Scanning](security/guardrails.md#tool-output-scanning) for details.
The runner registers a guardrail hook that scans tool output for secrets and PII patterns. The hook passes `hctx.ToolName` to the guardrail engine, enabling per-tool exemptions via `allow_tools` config. See [Tool Output Scanning](../security/guardrails.md#tool-output-scanning) for details.

```go
hooks.Register(engine.AfterToolExec, func(ctx context.Context, hctx *engine.HookContext) error {
Expand All @@ -101,7 +101,7 @@ When skills declare guardrails in their `SKILL.md` frontmatter, the runner regis

These hooks complement the global guardrail hooks (secrets/PII scanning) and fire in addition to them. Skill guardrails are loaded from build artifacts or parsed at runtime from `SKILL.md` — no `forge build` step is required.

For pattern syntax and configuration, see [Skill Guardrails](security/guardrails.md#skill-guardrails).
For pattern syntax and configuration, see [Skill Guardrails](../security/guardrails.md#skill-guardrails).

## Audit Logging

Expand Down
4 changes: 2 additions & 2 deletions docs/core-concepts/how-forge-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Messaging platform integrations that implement the `channels.ChannelPlugin` inte

### forge-ui — Web Dashboard

Local web dashboard for managing agents from the browser. Single Go module embedded into the `forge` binary. See [Dashboard](dashboard.md) for details.
Local web dashboard for managing agents from the browser. Single Go module embedded into the `forge` binary. See [Dashboard](../reference/web-dashboard.md) for details.

### forge-skills — Skill System

Expand Down Expand Up @@ -360,4 +360,4 @@ The A2A server adds:
- **Rate limiting** — Per-IP token bucket middleware (read: 60 req/min burst 10, write: 10 req/min burst 3) with 429 responses and `Retry-After` headers; stale visitors evicted automatically
- **Request size limits** — `MaxHeaderBytes` (1 MiB) and `http.MaxBytesReader` (2 MiB) on request bodies; returns 413 on excess

See [Egress Security](security/egress.md) for details.
See [Egress Security](../security/egress-control.md) for details.
6 changes: 3 additions & 3 deletions docs/core-concepts/runtime-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,17 +243,17 @@ The runtime configures a `FilesDir` for tool-generated files (e.g., from `file_c
memory/ ← long-term memory
```

The `FilesDir` is set via `LLMExecutorConfig.FilesDir` and made available to tools through `runtime.FilesDirFromContext(ctx)`. See [Tools — File Create](tools.md#file-create) for details.
The `FilesDir` is set via `LLMExecutorConfig.FilesDir` and made available to tools through `runtime.FilesDirFromContext(ctx)`. See [Tools — File Create](tools-and-builtins.md#file-create) for details.

## Conversation Memory

For details on session persistence, context window management, compaction, and long-term memory, see [Memory](memory.md).
For details on session persistence, context window management, compaction, and long-term memory, see [Memory](memory-system.md).

## Hooks

The engine fires hooks at key points in the loop. See [Hooks](hooks.md) for details.

The runner registers five hook groups: logging, audit, progress, global guardrail hooks, and skill guardrail hooks. Global guardrails use the `GuardrailChecker` interface backed by the `github.com/initializ/guardrails` library — the `AfterToolExec` hook scans tool output for secrets and PII, redacting or blocking before results enter the LLM context. Guardrail config is loaded from `guardrails.json` (file mode) or MongoDB (DB mode). Skill guardrail hooks enforce domain-specific rules declared in `SKILL.md` — blocking commands, redacting output, intercepting capability enumeration probes, and replacing binary-enumerating responses. Skill guardrails are loaded from build artifacts or parsed directly from `SKILL.md` at runtime (no `forge build` required). See [Guardrails](security/guardrails.md) for full details.
The runner registers five hook groups: logging, audit, progress, global guardrail hooks, and skill guardrail hooks. Global guardrails use the `GuardrailChecker` interface backed by the `github.com/initializ/guardrails` library — the `AfterToolExec` hook scans tool output for secrets and PII, redacting or blocking before results enter the LLM context. Guardrail config is loaded from `guardrails.json` (file mode) or MongoDB (DB mode). Skill guardrail hooks enforce domain-specific rules declared in `SKILL.md` — blocking commands, redacting output, intercepting capability enumeration probes, and replacing binary-enumerating responses. Skill guardrails are loaded from build artifacts or parsed directly from `SKILL.md` at runtime (no `forge build` required). See [Guardrails](../security/guardrails.md) for full details.

## Streaming

Expand Down
2 changes: 1 addition & 1 deletion docs/core-concepts/skill-md-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Skill scripts run in a restricted environment via `SkillCommandExecutor`:
- **OAuth token resolution**: When `OPENAI_API_KEY` is set to `__oauth__`, the executor resolves OAuth credentials and injects the access token, `OPENAI_BASE_URL`, and the configured model as `REVIEW_MODEL`
- **Configurable timeout**: Each skill declares a `timeout_hint` in its YAML frontmatter (e.g., 300s for research)
- **No shell execution**: Scripts run via `bash <script> <json-input>`, not through a shell interpreter
- **Egress proxy enforcement**: When egress mode is `allowlist` or `deny-all`, a local HTTP/HTTPS proxy is started and `HTTP_PROXY`/`HTTPS_PROXY` env vars are injected into subprocess environments, ensuring `curl`, `wget`, Python `requests`, and other HTTP clients route through the same domain allowlist used by in-process tools (see [Egress Security](security/egress.md))
- **Egress proxy enforcement**: When egress mode is `allowlist` or `deny-all`, a local HTTP/HTTPS proxy is started and `HTTP_PROXY`/`HTTPS_PROXY` env vars are injected into subprocess environments, ensuring `curl`, `wget`, Python `requests`, and other HTTP clients route through the same domain allowlist used by in-process tools (see [Egress Security](../security/egress-control.md))

### Symlink Escape Detection

Expand Down
10 changes: 5 additions & 5 deletions docs/core-concepts/tools-and-builtins.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ tools:
| 2 | **Binary allowlist** | Only pre-approved binaries can execute |
| 3 | **Binary resolution** | Binaries are resolved to absolute paths via `exec.LookPath` at startup |
| 4 | **Argument validation** | Rejects arguments containing `$(`, backticks, newlines, or `file://` URLs |
| 5 | **File protocol blocking** | Arguments containing `file://` (case-insensitive) are blocked to prevent filesystem traversal via `curl file:///etc/passwd` (see [File Protocol Blocking](security/guardrails.md#file-protocol-blocking)) |
| 6 | **Path confinement** | Path arguments inside `$HOME` but outside `workDir` are blocked (see [Path Containment](security/guardrails.md#path-containment)) |
| 5 | **File protocol blocking** | Arguments containing `file://` (case-insensitive) are blocked to prevent filesystem traversal via `curl file:///etc/passwd` (see [File Protocol Blocking](../security/guardrails.md#file-protocol-blocking)) |
| 6 | **Path confinement** | Path arguments inside `$HOME` but outside `workDir` are blocked (see [Path Containment](../security/guardrails.md#path-containment)) |
| 7 | **Timeout** | Configurable per-command timeout (default: 120s) |
| 8 | **No shell** | Uses `exec.CommandContext` directly — no shell expansion |
| 9 | **Working directory** | `cmd.Dir` set to `workDir` so relative paths resolve within the agent directory |
| 10 | **Environment isolation** | Only `PATH`, `HOME`, `LANG`, explicit passthrough vars, proxy vars, `OPENAI_ORG_ID` (when set), `GH_CONFIG_DIR` (auto-set to real `~/.config/gh` **only for `gh`**), and `KUBECONFIG`/`NO_PROXY` (**only for `kubectl`/`helm`** — see below). `HOME` is overridden to `workDir` to prevent `~` expansion from reaching the real home directory |
| 11 | **Output limits** | Configurable max output size (default: 1MB) to prevent memory exhaustion |
| 12 | **Skill guardrails** | Skill-declared `deny_commands` and `deny_output` patterns block/redact command inputs and outputs (see [Skill Guardrails](security/guardrails.md#skill-guardrails)) |
| 12 | **Skill guardrails** | Skill-declared `deny_commands` and `deny_output` patterns block/redact command inputs and outputs (see [Skill Guardrails](../security/guardrails.md#skill-guardrails)) |
| 13 | **Custom tool entrypoint validation** | Custom tool entrypoints are validated: rejects empty, absolute, or `..`-containing paths; resolves symlinks and verifies the target stays within the project directory and is a regular file |

### KUBECONFIG and NO_PROXY Scoping
Expand All @@ -133,7 +133,7 @@ When `HOME` is overridden to `workDir`, `kubectl` and `helm` lose access to `~/.
| `KUBECONFIG` | Explicit `KUBECONFIG` if set, else `<real-home>/.kube/config` | Passes through the active kubeconfig |
| `NO_PROXY` | K8s API server hostname(s) | Bypasses the egress proxy for cluster connections |

If `KUBECONFIG` is explicitly set in the environment (e.g., via `docker run -e KUBECONFIG=...` or after [KUBECONFIG materialization](runtime.md#kubeconfig-materialization)), that value is passed through directly. Otherwise, `cli_execute` falls back to the real `~/.kube/config`. `NO_PROXY` is extracted from the kubeconfig's `clusters[].cluster.server` field. Other binaries do not receive these variables.
If `KUBECONFIG` is explicitly set in the environment (e.g., via `docker run -e KUBECONFIG=...` or after [KUBECONFIG materialization](runtime-engine.md#kubeconfig-materialization)), that value is passed through directly. Otherwise, `cli_execute` falls back to the real `~/.kube/config`. `NO_PROXY` is extracted from the kubeconfig's `clusters[].cluster.server` field. Other binaries do not receive these variables.

## File Create

Expand Down Expand Up @@ -167,7 +167,7 @@ Filenames with path separators (`/`, `\`) or traversal patterns (`..`) are rejec

## Memory Tools

When [long-term memory](memory.md) is enabled, two additional tools are registered:
When [long-term memory](memory-system.md) is enabled, two additional tools are registered:

- **`memory_search`** — Hybrid vector + keyword search across stored memory files
- **`memory_get`** — Read specific memory files by path
Expand Down
2 changes: 1 addition & 1 deletion docs/deployment/production-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ forge export --pretty --include-schemas
forge export --simulate-import
```

See [Command Integration](command-integration.md) for the full integration guide.
See [Command Integration](../reference/command-integration.md) for the full integration guide.
2 changes: 1 addition & 1 deletion docs/getting-started/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,4 @@ Releases are automated via GoReleaser:
5. GitHub Actions runs GoReleaser to build and publish binaries

---
← [Command Integration](command-integration.md) | [Back to README](../README.md)
← [Command Integration](../reference/command-integration.md) | [Back to README](../../README.md)
2 changes: 1 addition & 1 deletion docs/reference/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,4 +505,4 @@ forge ui --dir /path/to/workspace --port 4200
forge ui --no-open
```

See [Dashboard](dashboard.md) for full documentation.
See [Dashboard](web-dashboard.md) for full documentation.
2 changes: 1 addition & 1 deletion docs/reference/web-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ The Skill Builder uses the agent's own LLM provider to power a chat conversation

### Validation Rules

The validator enforces the [SKILL.md format](skills.md):
The validator enforces the [SKILL.md format](../core-concepts/skill-md-format.md):

| Check | Level | Description |
|-------|-------|-------------|
Expand Down
20 changes: 10 additions & 10 deletions docs/security/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Allowed domains are resolved from three sources:

Localhost (`127.0.0.1`, `::1`, `localhost`) is always allowed in all modes.

For full details on egress enforcement, see **[Egress Security](egress.md)**.
For full details on egress enforcement, see **[Egress Security](egress-control.md)**.

---

Expand Down Expand Up @@ -174,15 +174,15 @@ Forge provides AES-256-GCM encrypted secret storage with Argon2id key derivation

At startup, the runtime detects when the same secret value is shared across different purpose categories (e.g., `OPENAI_API_KEY` and `TELEGRAM_BOT_TOKEN` having the same value). This prevents credential reuse mistakes that could escalate the impact of a single token compromise. Categories: `llm`, `search`, `telegram`, `slack`.

For full details, see **[Secrets Management](secrets.md)**.
For full details, see **[Secrets Management](secret-management.md)**.

---

## Build Integrity

Forge supports Ed25519 signing and SHA-256 checksumming of build artifacts for supply chain integrity. At runtime, `forge run` can verify artifacts against trusted keys before execution.

For full details, see **[Build Signing & Verification](signing.md)**.
For full details, see **[Build Signing & Verification](build-signing.md)**.

---

Expand Down Expand Up @@ -267,11 +267,11 @@ Production builds enforce:

| Document | Description |
|----------|-------------|
| [Egress Security](egress.md) | Deep dive into egress enforcement: IP validation, SafeDialer, profiles, modes, domain matching, proxy architecture, NetworkPolicy |
| [Secrets Management](secrets.md) | Encrypted storage, per-agent secrets, passphrase handling |
| [Build Signing & Verification](signing.md) | Key management, build signing, runtime verification |
| [Egress Security](egress-control.md) | Deep dive into egress enforcement: IP validation, SafeDialer, profiles, modes, domain matching, proxy architecture, NetworkPolicy |
| [Secrets Management](secret-management.md) | Encrypted storage, per-agent secrets, passphrase handling |
| [Build Signing & Verification](build-signing.md) | Key management, build signing, runtime verification |
| [Content Guardrails](guardrails.md) | PII detection, jailbreak protection, custom rules |
| [Architecture](../architecture.md) | System design, module layout, and data flows |
| [Tools](../tools.md) | Tool system including `cli_execute` security layers |
| [Skills](../skills.md) | Skill definitions and runtime execution |
| [Commands](../commands.md) | CLI reference including security-related flags |
| [Architecture](../core-concepts/how-forge-works.md) | System design, module layout, and data flows |
| [Tools](../core-concepts/tools-and-builtins.md) | Tool system including `cli_execute` security layers |
| [Skills](../skills/writing-custom-skills.md) | Skill definitions and runtime execution |
| [Commands](../reference/cli-reference.md) | CLI reference including security-related flags |
4 changes: 2 additions & 2 deletions docs/skills/embedded-skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,13 @@ This registers fourteen tools:

**Pagination:** List tools (`github_list_prs`, `github_list_stargazers`, `github_list_forks`, `github_pr_author_profiles`, `github_stargazer_profiles`) support `page` (1-based) and `per_page` (default 30, max 100) parameters. Responses include `pagination.has_next_page` to indicate more results are available.

**PII exemption:** Profile-returning tools (`github_get_user`, `github_pr_author_profiles`, `github_stargazer_profiles`) are pre-configured in the default policy scaffold's `no_pii` `allow_tools` list, so they can return public profile data (emails, bios) without triggering PII guardrails. See [Per-Tool PII Exemptions](security/guardrails.md#per-tool-pii-exemptions).
**PII exemption:** Profile-returning tools (`github_get_user`, `github_pr_author_profiles`, `github_stargazer_profiles`) are pre-configured in the default policy scaffold's `no_pii` `allow_tools` list, so they can return public profile data (emails, bios) without triggering PII guardrails. See [Per-Tool PII Exemptions](../security/guardrails.md#per-tool-pii-exemptions).

Requires: `gh`, `git`, `jq`. Optional: `GH_TOKEN`. Egress: `api.github.com`, `github.com`.

### Code-Agent Skill

The `code-agent` skill enables autonomous code generation and modification using [builtin code-agent tools](tools.md#code-agent-tools):
The `code-agent` skill enables autonomous code generation and modification using [builtin code-agent tools](../core-concepts/tools-and-builtins.md#code-agent-tools):

```bash
forge skills add code-agent
Expand Down
Loading
Loading