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
39 changes: 24 additions & 15 deletions .agents/skills/gilmanlab-documentation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ all-purpose documentation format:
- Use [arc42](https://docs.arc42.org/) concepts selectively when describing
architecture. Do not require a complete arc42 document.

Documentation is code: keep it beside the system it describes, review it with
implementation changes, and maintain one canonical source for each fact.
Documentation is code: review it with implementation changes and maintain one
canonical source for each fact.

## Locate the content root

`<docs-root>` means the content directory configured by the repository's site
generator. If the repository has no site generator, use `<repo>/docs/`.
`<docs-root>` is the meta repository's `docs/docs/` content directory, built by
the MkDocs project at `<meta-repo>/docs/`. All GilmanLab documentation lives
there, regardless of which repository owns the implementation.

Inspect the existing configuration before creating directories. Never create a
second documentation tree beside an established content root.
Never create a documentation tree inside a sub-repository. If one exists, treat
it as a migration candidate into the central site, not as a second content
root.

## Standard structure

Expand Down Expand Up @@ -68,7 +70,8 @@ merging their content.

## Authoring workflow

1. Identify the owning repository and its configured `<docs-root>`.
1. Search the central `<docs-root>` for an existing canonical document before
writing; extend or link instead of duplicating.
2. Classify the reader's need using the table above.
3. For a decision or design, copy the corresponding template from
`references/` beside this skill.
Expand All @@ -77,9 +80,10 @@ merging their content.
5. Link canonical configuration, issues, experiments, and related documents.
Do not copy exact values that already have a better source of truth.
6. When implementation changes behavior, update affected architecture,
reference, and runbook documents in the same change.
7. Build the documentation site and check links using the repository's normal
task before merging.
reference, and runbook documents as a companion change in the meta
repository.
7. Build the documentation site with `moon run docs:build` and fix strict-mode
failures before merging.

## Architecture contract

Expand Down Expand Up @@ -180,8 +184,13 @@ concept tutorial or duplicate command reference.

## Cross-repository ownership

The repository that owns the implementation owns its documentation. For a
cross-repository design, choose the repository that owns the integration or
operational outcome, then link to it from the others. The meta repository may
provide navigation and genuinely cross-cutting architecture; it must not mirror
sub-repository documentation.
All documentation lives in the meta repository's central site; implementation
lives in the owning repositories. Namespace domain-specific reference material
by domain (for example `reference/networking/`), keep one global decision
sequence, and let design titles scope themselves.

The implementing repository's changes and their documentation updates ship as
companion changes: when a sub-repository change alters documented behavior,
update the central documents in the same unit of work. Keep exact values
(addresses, VLANs, ports, hardware) in one canonical reference document and
link to it from every other document.
77 changes: 77 additions & 0 deletions .github/workflows/docs-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: GitHub Pages

on:
pull_request:
branches:
- master
push:
branches:
- master
workflow_dispatch:

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: Build documentation
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
persist-credentials: false

- name: Setup mise
uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
with:
version: 2026.6.14
cache: true

- name: Resolve uv cache directory
id: uv-cache
run: echo "dir=$(uv cache dir)" >> "$GITHUB_OUTPUT"

- name: Cache uv downloads
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
with:
path: ${{ steps.uv-cache.outputs.dir }}
key: ${{ runner.os }}-uv-docs-${{ hashFiles('docs/uv.lock') }}
restore-keys: |
${{ runner.os }}-uv-docs-

- name: Build documentation
run: moon run docs:build --summary minimal

- name: Configure Pages
if: ${{ github.event_name != 'pull_request' }}
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- name: Upload Pages artifact
if: ${{ github.event_name != 'pull_request' }}
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: docs/build

deploy:
name: Deploy documentation
if: ${{ github.event_name != 'pull_request' }}
needs:
- build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,19 @@
.claude/
.journal/
.wt/
networking/
/networking/

# Moon
.moon/cache/
.moon/docker/

# mise local overrides
mise.local.toml
.mise.local.toml

# Python and MkDocs
__pycache__/
*.py[cod]
.venv/
docs/.venv/
docs/build/
12 changes: 12 additions & 0 deletions .moon/workspace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
projects:
sources:
docs: 'docs'

defaultProject: 'docs'

vcs:
defaultBranch: 'master'
provider: 'github'

pipeline:
installDependencies: false
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,12 @@ read and follow `.agents/skills/gilmanlab-documentation/SKILL.md` from the meta
repository root. Its document classification, ownership rules, lifecycle, and
decision and design templates are required. Keep this skill canonical in the
meta repository; do not copy it into each sub-repository.

All GilmanLab documentation is centralized in this repository under `docs/`.
Sub-repositories must not create their own `docs/` trees; a documentation
change motivated by sub-repository work is a companion change in this
repository. When a sub-repository change alters behavior that is documented
here, update the affected documents in the same unit of work.

Build and verify the site with `moon run docs:build` before merging
documentation changes.
1 change: 1 addition & 0 deletions docs/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14.7
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
status: accepted
date: 2026-08-14
---

# ADR-0001: Use VyOS for Layer 3 and Dedicated Switches for Layer 2

## Context and Problem Statement

The core network needs explicit ownership for switching, routing, and traffic
policy. The network uses a VyOS gateway, a MikroTik CRS309-1G-8S+IN core switch,
and a TRENDnet TEG-3102WS management/OOB switch. Which devices own each network
function?

## Decision Drivers

- Keep routed gateways and firewall policy on one device.
- Keep switch configuration focused on Layer 2 transport and physical links.
- Make the enforcement point for traffic between routed lab segments explicit.
- Carry MS-02 management/OOB traffic on its dedicated copper switch.
- Use the selected VyOS, MikroTik, and TRENDnet hardware.

## Considered Options

- Use VyOS for Layer 3 and dedicated switches for Layer 2.
- Use MikroTik for Layer 2 and Layer 3, with VyOS at the external edge.
- Use one flat Layer 2 lab network, with VyOS as its external gateway.

## Decision Outcome

Use VyOS for routed lab gateways, route selection, firewall policy, and NAT. Use
the MikroTik CRS309-1G-8S+IN for core Layer 2 switching and VLAN transport. Use
the TRENDnet TEG-3102WS for Layer 2 management/OOB connectivity from both
non-SFP NICs on each MS-02. The TEG-3102WS uplinks directly to the VP6630, which
provides the management/OOB gateway and firewall policy.

DHCP, DNS, and time-service ownership are outside the scope of this decision.

### Consequences

- Good, because routed traffic has one policy-enforcement point.
- Good, because each device has a distinct configuration boundary.
- Good, because the MS-02 management/OOB links use a dedicated physical switch.
- Bad, because traffic between routed lab segments depends on VyOS.
- Bad, because routed segments carried through the CRS309-1G-8S+IN depend on
its trunk to VyOS.
- Bad, because MS-02 management/OOB access depends on the TEG-3102WS and its
uplink to the VP6630.

### Confirmation

The implementation conforms to this decision when:

- VyOS owns the gateway address for each routed lab segment, including the
management/OOB segment.
- VyOS contains the firewall and NAT policy for routed lab traffic.
- Neither switch routes traffic between lab segments.
- CRS309-1G-8S+IN configuration defines core VLAN membership, trunks, access
ports, and physical link aggregation.
- TEG-3102WS configuration and cabling connect both non-SFP NICs from each MS-02
to the VP6630 management/OOB gateway.

Management addresses on the switches do not violate this decision.

## Pros and Cons of the Options

### VyOS Layer 3 and Dedicated Layer 2 Switches

- Good, because routing and firewall policy use the same configuration
boundary.
- Good, because the switches remain independent of higher-level traffic policy.
- Good, because core and management/OOB traffic use separate physical switches.
- Bad, because VyOS is on the forwarding path for all routed lab traffic.
- Bad, because each switch is a failure boundary for its connected links.

### MikroTik Layer 2 and Layer 3

- Good, because the core switch can route traffic without sending it through
the VyOS trunk.
- Bad, because firewall and routing ownership would be split between devices.
- Bad, because the network would need policy coordination between MikroTik and
VyOS.

### Flat Layer 2 Lab Network

- Good, because it requires fewer routed interfaces and policies.
- Bad, because it cannot enforce boundaries between lab network functions.
- Bad, because broadcasts and Layer 2 failures share one domain.

## More Information

See the [Lab v2 core network design](../designs/drafts/lab-v2-core-network.md)
and [hardware reference](../reference/networking/hardware.md).
Loading