From 38e6514fce234a77c7a80948ed608af3fda3217c Mon Sep 17 00:00:00 2001 From: Dmitry Lyfar Date: Wed, 12 Aug 2026 19:37:03 +1200 Subject: [PATCH] Update copilot instructions; add knowledge base --- .github/copilot-instructions.md | 93 +++---------------------------- .github/knowledge.instructions.md | 5 ++ .github/knowledge/README.md | 4 ++ .github/knowledge/daemon.md | 59 ++++++++++++++++++++ 4 files changed, 75 insertions(+), 86 deletions(-) create mode 100644 .github/knowledge.instructions.md create mode 100644 .github/knowledge/README.md create mode 100644 .github/knowledge/daemon.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 802cd9fb6..9152fb6de 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,106 +1,27 @@ # GitHub Copilot Instructions -This file provides general project context for GitHub Copilot. For review-specific guidance, see: +For review-specific guidance, see: + - **Code Review**: `.github/agents/code-review.agent.md` - **Documentation Review**: `.github/skills/documentation-review/SKILL.md` ## Project Overview -Workshop is a tool for defining and handling ephemeral development environments. It uses a client-server architecture where `workshopd` daemon exposes a RESTful API to clients. The project is written in Go and distributed as a Snap package. - -## Tech Stack - -- **Language**: Go 1.25+ -- **Container Backend**: LXD (primary abstraction target) -- **Packaging**: Snap (Snapcraft) -- **CLI Framework**: Cobra -- **Testing**: Go unit tests (gocheck) + Spread (integration/e2e) -- **Documentation**: Sphinx (reStructuredText) -- **CI**: GitHub Actions - -## Repository Structure +Workshop is a tool for defining and handling ephemeral development environments. It uses a client-server architecture where `workshopd` daemon exposes a RESTful API to clients. The project is written in Go, packaged as a Snap, and uses LXD as the container backend. Unit tests use gocheck; end-to-end tests use Spread. -### Core Directories -- `cmd/` — CLI entry points (`workshop`, `workshopd`, `workshopctl`, `sdk`, `internal`) -- `client/` — Go client library for RESTful API communication -- `internal/` — Private packages (`daemon`, `overlord`, `workshop`, `interfaces`, `sdk`, etc.) -- `tests/` — E2E test suites using Spread (`main/`, `integration/`, `docs-*/`, `lib/`) -- `snap/` — Snap packaging configuration -- `docs/` — Sphinx documentation source and configuration (`Makefile`, `conf.py`, `contributing.rst`) - -### Build Configuration -- `go.mod` / `go.sum` — Go module dependencies -- `.golangci.yaml` / `.golangci.incremental.yaml` — Linting configuration -- `.spread.yaml` — E2E testing with Spread framework -- `snap/snapcraft.yaml` — Snap package definition -- `docs/Makefile` — Sphinx documentation build script +Key directories: `cmd/` (CLI entry points), `client/` (Go client library), `internal/` (core packages: `daemon`, `overlord`, `workshop`, `interfaces`, `sdk`). ## Coding Guidelines -See [`docs/coding-style-guide.md`](../docs/coding-style-guide.md) for detailed standards. Key points: - -- **Error messages**: Lowercase, no trailing punctuation, actionable (`what was attempted: why it went wrong`) -- **Error handling**: Consistent `if err := f(); err != nil { return err }` pattern -- **Code organization**: Early returns over nested conditions; keep coupled elements adjacent -- **Testing**: Unit tests (`*_test.go`) adjacent to implementation; Spread tests for integration - -## Common Tasks - -### Running Tests -- **Unit Tests**: Run `go test ./...` in the root directory. -- **E2E Tests**: Use `spread` (requires external setup). Example: `spread tests/integration/`. +See [`docs/coding-style-guide.md`](../docs/coding-style-guide.md) for detailed standards. -### Linting -- Run `golangci-lint run` to check for style and error handling issues. +## Development Workflow -### Building Documentation -- Navigate to `docs/` and run `make html` to build static HTML. -- Run `make run` in `docs/` to build and serve locally. - -### Running Locally -- Quick path: `go tool try` — builds, starts `workshopd` against a temporary session, and drops into a pre-configured subshell. Exit to tear down; `--keep` retains the session. -- Manual: `go install ./cmd/...` then `workshopd run --create-dirs` (requires `WORKSHOP_DATA` and `WORKSHOP_CACHE` env vars set). - -## Available Resources - -- **Contributing Guide**: [`docs/contributing/development.rst`](../docs/contributing/development.rst) — Setup, testing, workflow -- **Documentation Style**: [`docs/doc-style-guide.md`](../docs/doc-style-guide.md) — reST/Markdown conventions -- **PR Template**: [`.github/pull_request_template.md`](.github/pull_request_template.md) — Self-review checklist -- **Code Review Agent**: [`.github/agents/code-review.agent.md`](.github/agents/code-review.agent.md) — For PR code reviews -- **Documentation Review Skill**: [`.github/skills/documentation-review/SKILL.md`](skills/documentation-review/SKILL.md) — For documentation reviews +See [`docs/contributing/development.rst`](../docs/contributing/development.rst) for setup, testing, and workflow details. ## Related Repositories These external repositories provide authoritative context for the Workshop project: - https://github.com/canonical/sdkcraft — SDKcraft utility codebase for packaging and publishing SDKs -- Individual SDK implementations live as `canonical/-sdk` repositories (e.g. `ollama-sdk`, `cuda-toolkit-sdk`, `zephyr-sdk`); see `docs/reference/reference-implementations.rst` for the curated themed list - https://github.com/canonical/reference-workshops — Reference workshop implementations demonstrating SDK usage patterns - -## GitHub Actions Workflows - -- `lint.yaml` — golangci-lint on Go code -- `unit-tests.yaml` — Go unit tests -- `spread.yaml` — E2E tests with Spread -- `cover.yaml` — Coverage reports -- `automatic-doc-checks.yml` — Sphinx builds (fail on warnings) -- `doc-cover.yaml` — Documentation coverage map generation -- `doc-update-sdk-schema.yml` — Updates SDK schema in docs -- `fix-redirected-links.yml` — Updates selected redirecting documentation links -- `release.yaml` — Builds release snaps + generates CLI reference PR -- `fixup.yaml` — Commit message format validation -- `scanning.yml` — Security scanning -- `markdown-style-checks.yml` — Markdown linting -- `build-deps.yaml` — Build dependencies check -- `lxd-candidate-check.yaml` — Checks LXD candidate channel -- `staging.yaml` — Rejects staged test SDKs -- `update-sphinx-stack.yaml` — Updates Sphinx Stack files and documentation dependencies -- `zizmor.yaml` — Audits GitHub Actions workflows - -## Evolution Note - -These instructions are living documentation. When Copilot misbehaves: -1. Note the specific failure mode -2. Identify which instruction file should address it -3. Propose minimal, high-signal edits (avoid essay-style additions) -4. Test with focused prompts before committing changes diff --git a/.github/knowledge.instructions.md b/.github/knowledge.instructions.md new file mode 100644 index 000000000..aee37424c --- /dev/null +++ b/.github/knowledge.instructions.md @@ -0,0 +1,5 @@ +--- +applyTo: "**" +--- + +Before implementing, reviewing, or planning any change, read the relevant subsystem note in [`.github/knowledge/`](.github/knowledge/). diff --git a/.github/knowledge/README.md b/.github/knowledge/README.md new file mode 100644 index 000000000..50ca59fde --- /dev/null +++ b/.github/knowledge/README.md @@ -0,0 +1,4 @@ +# Workshop knowledge base + +Curated, agent-facing notes about how Workshop actually works: architecture +maps, invariants, and gotchas. diff --git a/.github/knowledge/daemon.md b/.github/knowledge/daemon.md new file mode 100644 index 000000000..94e5290a9 --- /dev/null +++ b/.github/knowledge/daemon.md @@ -0,0 +1,59 @@ +# workshopd daemon + +**Scope**: Consult when working on the daemon lifecycle, state manangers +snapcraft.yaml or snap hooks or anything that reads/writes the data, common, or cache directories. + +Daemon lifecycle logic lives in `internal/daemon`. + +State managers are located in `internal/overlord/cmdstate`, `internal/overlord/healthstate`, `internal/overlord/hookstate`, +`internal/overlord/ifacestate`, `internal/overlord/sdkstate`, `internal/overlord/workshopstate`. + +## Socket-activated daemon + +`workshopd` is a **socket-activated systemd notify daemon** that deactivates +if the ensure cycle has run at least once, there are no active connections +for a period of time and no active changes running. + +Implications of the socket activation that the daemon relies on: + +- `workshop.bin` mounts are recreated for all existing + workshops on every daemon start up. +- All interface connections are reloaded from `state.json` on every daemon start up (see + `internal/overlord/ifacestate/ifacemgr.go:InterfaceManager.StartUp()`). +- Xauthority cookie is updated on every daemon startup. That allows the daemon to have + an up to date cookie after the user's logout from an X11 session with a subsequent login. +- Anything that is not written to `state.json` or to the workshop's OR SDK's + LXD configuration is lost on deactivation. E.g. the state's cache that the daemon uses for verbose logs, see `internal/overlord/state/state.go:State.Cache()`. + +## Degraded mode + +Triggered when `syscheck.CheckSystem()` fails (LXD missing/incompatible/down; out of storage space). + +- Blocks all non-`GET` requests with the degraded error; `GET` still works. +- A recovery ticker re-runs `CheckSystem()` continuously and clears degraded + mode automatically — it also detects LXD disappearing _after_ startup. + +## Directory layout + +Three host roots, each overridable by an env var, with snap-specific defaults: + +| Role | Var | Default (non-snap) | Snap value | Refresh behavior | +| ------ | ----------------- | --------------------- | ----------------------------- | -------------------------------------------- | +| Data | `WORKSHOP_DATA` | `/var/lib/workshop` | `$SNAP_DATA` | **Per revision** (tied to installed version) | +| Common | `WORKSHOP_COMMON` | falls back to Data | `$SNAP_COMMON/workshop` | **Shared** across revisions | +| Cache | `WORKSHOP_CACHE` | `/var/cache/workshop` | `$SNAP_COMMON/workshop/cache` | Shared | + +Key distinction: **Data** is revision-scoped (`$SNAP_DATA`), **Common** survives +snap refreshes (`$SNAP_COMMON`). + +## Invariants + +**Security backends and interfaces are registered before `ensureBackendInit` runs.** + +- **Why**: if `ensureBackendInit` runs first, `repo.Plug` returns nil and + `reloadConnections` silently skips every connection; `backendReady` then + latches true, so the later `StartUp()` call is a no-op. +- **Where enforced**: registration ordering in `InterfaceManager.StartUp()`, + `internal/overlord/ifacestate/ifacemgr.go`. +- **How it breaks**: reordering registration or the syscheck - connections never + load and no error is surfaced.