Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd0910287a | ||
|
|
063623cb9f | ||
|
|
ae52aab843 | ||
|
|
2acc1c0eb6 | ||
|
|
a31af2e236 | ||
|
|
68a763b942 | ||
|
|
d9dae396bc | ||
|
|
7816733e5e |
@@ -0,0 +1,135 @@
|
|||||||
|
# dependency-graph
|
||||||
|
|
||||||
|
Map of the oblachno ecosystem. Knows which repo produces what, which
|
||||||
|
repos depend on which, and the correct order for cross-repo changes.
|
||||||
|
|
||||||
|
## When to Invoke
|
||||||
|
|
||||||
|
Invoke this skill when:
|
||||||
|
- Changes span multiple repos
|
||||||
|
- A change in one repo requires version bumps in downstream repos
|
||||||
|
- Deploying infrastructure that depends on published packages/images
|
||||||
|
- Verifying the ecosystem is in a consistent state before deployment
|
||||||
|
- Determining which repos to update and in what order
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- All repos cloned under `/home/emo/dev/ideas/oblachno/`
|
||||||
|
- `.env` with `DEVELOPER_GITEA_API_TOKEN` in each repo
|
||||||
|
|
||||||
|
## Ecosystem Map
|
||||||
|
|
||||||
|
```
|
||||||
|
devx (PyPI package)
|
||||||
|
/ | \
|
||||||
|
/ | \
|
||||||
|
grm sso-bridge infra
|
||||||
|
(PyPI) (PyPI+Docker) (deploys all)
|
||||||
|
| | |
|
||||||
|
v v v
|
||||||
|
infra bump infra bump staging
|
||||||
|
(auto PR) (auto PR) production
|
||||||
|
|
|
||||||
|
mattermost-oidc (Docker image)
|
||||||
|
(infra pulls :latest at deploy)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repositories
|
||||||
|
|
||||||
|
| Repo | Produces | Consumers | Release Trigger |
|
||||||
|
|------|----------|-----------|-----------------|
|
||||||
|
| `devx` | PyPI package `devx` | grm, sso-bridge, infra | User-facing changes to `src/devx/**` |
|
||||||
|
| `grm` | PyPI package `grm` | infra | User-facing changes to `src/grm/**` or `ansible/**` |
|
||||||
|
| `sso-bridge` | PyPI package `sso_bridge` + Docker image | infra | User-facing changes to `src/sso_bridge/**` or `ansible/**` |
|
||||||
|
| `infra` | Staging/production deployment | (end users) | User-facing changes + nightly gate |
|
||||||
|
| `mattermost-oidc` | Docker image `mattermost-oidc` | infra (pulls at deploy) | `Dockerfile` or `build.yml` changes |
|
||||||
|
|
||||||
|
## Dependency Chain
|
||||||
|
|
||||||
|
### devx → all repos
|
||||||
|
|
||||||
|
devx publishes to the Gitea PyPI registry. grm, sso-bridge, and infra
|
||||||
|
pin devx in `pyproject.toml`:
|
||||||
|
```toml
|
||||||
|
"devx @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/devx.git@vX.Y.Z"
|
||||||
|
```
|
||||||
|
|
||||||
|
When devx publishes a new version:
|
||||||
|
1. grm, sso-bridge, and infra must bump their pinned devx version
|
||||||
|
2. This is currently manual — no auto-dependency-PR from devx
|
||||||
|
3. Each repo must `make setup` to pick up the new version
|
||||||
|
|
||||||
|
### grm → infra
|
||||||
|
|
||||||
|
grm publishes to PyPI. Its post-merge workflow auto-creates an infra
|
||||||
|
dependency PR via `devx.ci.create_dependency_pr --repo oblachno/infra
|
||||||
|
--package grm`. The PR bumps the pinned grm version in infra's
|
||||||
|
`pyproject.toml`.
|
||||||
|
|
||||||
|
### sso-bridge → infra
|
||||||
|
|
||||||
|
sso-bridge publishes to PyPI AND builds a Docker image. Its post-merge
|
||||||
|
workflow auto-creates an infra dependency PR via
|
||||||
|
`devx.ci.create_dependency_pr --repo oblachno/infra --package
|
||||||
|
sso_bridge`. The PR bumps the pinned sso_bridge version.
|
||||||
|
|
||||||
|
The Docker image is pulled by infra at deploy time (`sso-bridge:latest`).
|
||||||
|
|
||||||
|
### mattermost-oidc → infra
|
||||||
|
|
||||||
|
mattermost-oidc builds a Docker image tagged `:latest` and `:MM_VERSION`.
|
||||||
|
infra pulls `mattermost-oidc:latest` at deploy time. There is no
|
||||||
|
auto-dependency-PR — infra simply pulls the latest image.
|
||||||
|
|
||||||
|
### infra → staging/production
|
||||||
|
|
||||||
|
infra deploys to staging and production. The deployment:
|
||||||
|
1. Provisions VMs from golden images
|
||||||
|
2. Runs Ansible roles (including grm and sso-bridge roles)
|
||||||
|
3. Pulls Docker images (sso-bridge, mattermost-oidc)
|
||||||
|
4. Configures services
|
||||||
|
|
||||||
|
## Correct Order for Cross-Repo Changes
|
||||||
|
|
||||||
|
When a change spans multiple repos, follow this order:
|
||||||
|
|
||||||
|
1. **devx first** — if the change starts in devx, merge and publish devx
|
||||||
|
first. Wait for the PyPI publish job to complete.
|
||||||
|
2. **Bump devx in consumers** — in grm/sso-bridge/infra, bump the pinned
|
||||||
|
devx version, run `make setup`, verify tests pass, merge.
|
||||||
|
3. **grm/sso-bridge second** — merge and publish grm/sso-bridge. Wait
|
||||||
|
for the PyPI publish + Docker image build to complete.
|
||||||
|
4. **Auto-dependency-PRs** — grm/sso-bridge post-merge auto-creates infra
|
||||||
|
PRs to bump pinned versions. Wait for these PRs to appear.
|
||||||
|
5. **Merge infra dependency PRs** — review and merge the auto-created
|
||||||
|
infra PRs.
|
||||||
|
6. **infra last** — deploy to staging, validate, promote to production.
|
||||||
|
|
||||||
|
## State Verification Before Deployment
|
||||||
|
|
||||||
|
Before deploying infra, verify:
|
||||||
|
|
||||||
|
1. **devx version consistent** — all repos pin the same devx version
|
||||||
|
2. **grm published** — latest grm tag exists in PyPI
|
||||||
|
3. **sso-bridge published** — latest sso_bridge tag exists in PyPI
|
||||||
|
4. **sso-bridge image built** — latest sso-bridge Docker image exists
|
||||||
|
5. **mattermost-oidc image built** — latest mattermost-oidc image exists
|
||||||
|
6. **infra pins match published versions** — no stale pins
|
||||||
|
7. **Nightly gate green** — `NIGHTLY_STATUS` is not `failed`
|
||||||
|
|
||||||
|
## Quick Check Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check latest devx version
|
||||||
|
curl -sS https://git.oblachno.oblachno.fyi/api/v1/repos/oblachno-oss/devx/releases/latest | python3 -c "import json,sys; print(json.load(sys.stdin).get('tag_name','?'))"
|
||||||
|
|
||||||
|
# Check pinned devx version in each repo
|
||||||
|
for repo in grm sso-bridge infra; do
|
||||||
|
echo -n "$repo: "; grep 'devx @' /home/emo/dev/ideas/oblachno/$repo/pyproject.toml | grep -oP 'v[\d.]+'
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check latest sso-bridge image build
|
||||||
|
curl -sS -H "Authorization: token $DEVELOPER_GITEA_API_TOKEN" \
|
||||||
|
"https://git.oblachno.oblachno.fyi/api/v1/repos/oblachno/sso-bridge/actions/runs?per_page=5" \
|
||||||
|
| python3 -c "import json,sys; [print(r['id'],r['status'],r['conclusion']) for r in json.load(sys.stdin).get('workflow_runs',[]) if r.get('event')=='push']"
|
||||||
|
```
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# deployment-coordination
|
||||||
|
|
||||||
|
How grm releases propagate to infra. grm publishes a PyPI package and
|
||||||
|
auto-creates an infra dependency PR. Coordination ensures the PR is
|
||||||
|
merged before infra deploys.
|
||||||
|
|
||||||
|
## When to Invoke
|
||||||
|
|
||||||
|
Invoke this skill when:
|
||||||
|
- Changes to grm affect infra deployments
|
||||||
|
- Preparing a grm release that infra depends on
|
||||||
|
- Verifying infra has bumped to the latest grm version
|
||||||
|
- Coordinating a multi-repo change that includes grm
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- grm repo at `/home/emo/dev/ideas/oblachno/grm`
|
||||||
|
- `.env` with `DEVELOPER_GITEA_API_TOKEN`
|
||||||
|
- See `dependency-graph` skill for the full ecosystem map
|
||||||
|
|
||||||
|
## What grm Produces
|
||||||
|
|
||||||
|
grm publishes a Python package to the Gitea PyPI registry. infra pins it:
|
||||||
|
```toml
|
||||||
|
"grm @ git+https://git.oblachno.oblachno.fyi/oblachno-oss/grm.git@vX.Y.Z"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Release Flow
|
||||||
|
|
||||||
|
1. PR merged to master
|
||||||
|
2. Post-merge workflow runs `devx.ci.release` — classifies changes
|
||||||
|
3. If user-facing changes: git-cliff bumps version, creates tag, pushes
|
||||||
|
4. `devx.ci.publish` builds and publishes to Gitea PyPI registry
|
||||||
|
5. `devx.ci.create_dependency_pr --repo oblachno/infra --package grm`
|
||||||
|
auto-creates an infra PR to bump the pinned grm version
|
||||||
|
|
||||||
|
## Downstream Consumer
|
||||||
|
|
||||||
|
| Repo | Pin location | Auto-bump? |
|
||||||
|
|------|-------------|------------|
|
||||||
|
| infra | `pyproject.toml` | Yes — auto PR created by post-merge |
|
||||||
|
|
||||||
|
## Coordinating a grm Change
|
||||||
|
|
||||||
|
1. **Merge grm PR** — wait for post-merge publish + dependency-PR creation
|
||||||
|
2. **Verify publish** — check the new tag:
|
||||||
|
```bash
|
||||||
|
curl -sS -H "Authorization: token $DEVELOPER_GITEA_API_TOKEN" \
|
||||||
|
https://git.oblachno.oblachno.fyi/api/v1/repos/oblachno-oss/grm/releases/latest \
|
||||||
|
| python3 -c "import json,sys; print(json.load(sys.stdin).get('tag_name','?'))"
|
||||||
|
```
|
||||||
|
3. **Find the auto-created infra PR** — check infra for open PRs with
|
||||||
|
`dependency` label or title containing `bump grm`
|
||||||
|
4. **Review and merge the infra dependency PR** — verify the version bump,
|
||||||
|
run `make pytest-cov` in infra, add `ready-to-merge`
|
||||||
|
5. **Verify infra staging deploy** — after infra merges, staging deploy
|
||||||
|
picks up the new grm version
|
||||||
|
|
||||||
|
## State Verification
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Current grm version
|
||||||
|
grep '__version__' /home/emo/dev/ideas/oblachno/grm/src/grm/__init__.py
|
||||||
|
|
||||||
|
# What infra pins
|
||||||
|
grep 'grm @' /home/emo/dev/ideas/oblachno/infra/pyproject.toml | grep -oP 'v[\d.]+'
|
||||||
|
|
||||||
|
# Check for open infra dependency PRs
|
||||||
|
curl -sS -H "Authorization: token $DEVELOPER_GITEA_API_TOKEN" \
|
||||||
|
"https://git.oblachno.oblachno.fyi/api/v1/repos/oblachno/infra/pulls?state=open" \
|
||||||
|
| python3 -c "import json,sys; [print(p['number'],p['title']) for p in json.load(sys.stdin) if 'grm' in p.get('title','').lower()]"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Mistakes
|
||||||
|
|
||||||
|
- Merging the grm PR but ignoring the auto-created infra dependency PR
|
||||||
|
- Deploying infra before the dependency PR is merged — stale grm version
|
||||||
|
- Forgetting that grm also has an Ansible role used by infra at deploy time
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
# skill-creation
|
||||||
|
|
||||||
|
How to create, validate, and maintain Devin skills. Skills must be
|
||||||
|
clear, succinct, and actionable — no AI slop.
|
||||||
|
|
||||||
|
## When to Invoke
|
||||||
|
|
||||||
|
Invoke this skill when:
|
||||||
|
- Creating a new skill
|
||||||
|
- Amending an existing skill
|
||||||
|
- Evaluating whether a skill is needed
|
||||||
|
- Reviewing a PR that adds or modifies skills
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Skill directory: `.devin/skills/<skill-name>/SKILL.md`
|
||||||
|
- Validator: `tests/test_skills.py` (infra) or reference to it
|
||||||
|
- Tests: `tests/unit/test_skills_validation.py` (infra)
|
||||||
|
|
||||||
|
## When to Create a Skill
|
||||||
|
|
||||||
|
Create a skill when:
|
||||||
|
- An agent struggles with a task repeatedly (branch hygiene, PR order)
|
||||||
|
- A workflow has non-obvious ordering constraints (deployment coordination)
|
||||||
|
- A task requires specific tool usage over raw commands (CI monitoring)
|
||||||
|
- Multiple agents need shared context (dependency graph)
|
||||||
|
|
||||||
|
Do NOT create a skill for:
|
||||||
|
- One-off tasks (use a spec instead)
|
||||||
|
- Tasks already covered by AGENTS.md
|
||||||
|
- Tasks that are obvious from the Makefile or README
|
||||||
|
- Tasks that change frequently (skills should be stable)
|
||||||
|
|
||||||
|
## Skill Structure
|
||||||
|
|
||||||
|
Every skill MUST have:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <skill-name>
|
||||||
|
|
||||||
|
One-line description of what the skill does.
|
||||||
|
|
||||||
|
## When to Invoke
|
||||||
|
|
||||||
|
2-4 bullet points describing when to use this skill.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
What must exist before using the skill (venv, .env, tools).
|
||||||
|
|
||||||
|
## <Core Content>
|
||||||
|
|
||||||
|
The actual guidance. Keep it actionable.
|
||||||
|
|
||||||
|
## Verification (if applicable)
|
||||||
|
|
||||||
|
How to verify the skill's guidance works.
|
||||||
|
|
||||||
|
## Common Mistakes (if applicable)
|
||||||
|
|
||||||
|
What agents get wrong without this skill.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality Standards
|
||||||
|
|
||||||
|
### Do
|
||||||
|
- **Be specific.** Reference exact make targets, file paths, commands.
|
||||||
|
- **Be concise.** Each section should be scannable in under 30 seconds.
|
||||||
|
- **Be actionable.** Every paragraph should tell the agent what to DO.
|
||||||
|
- **Use tables** for command reference, mappings, and comparisons.
|
||||||
|
- **Use code blocks** for commands the agent should run.
|
||||||
|
- **Link to other skills** when related (e.g., "See `dependency-graph` skill").
|
||||||
|
|
||||||
|
### Don't
|
||||||
|
- **No preamble.** Don't start with "This skill helps agents..." — just state what it does.
|
||||||
|
- **No filler.** Don't repeat information from AGENTS.md or other skills.
|
||||||
|
- **No vague advice.** "Be careful with branches" is useless. "Run `git branch --show-current` before every commit" is useful.
|
||||||
|
- **No AI slop.** Don't write "In this comprehensive guide, we will explore..." — just give the guidance.
|
||||||
|
- **No redundant sections.** If "Common Mistakes" would repeat "When to Invoke", skip it.
|
||||||
|
- **No marketing.** Don't describe the skill as "powerful" or "comprehensive".
|
||||||
|
|
||||||
|
## Scope Rules
|
||||||
|
|
||||||
|
- **One skill per concern.** Don't mix branch hygiene with CI monitoring.
|
||||||
|
- **Project-specific, not generic.** Skills reference this repo's make targets, file paths, and conventions — not abstract advice.
|
||||||
|
- **Shared skills must be identical across repos.** Use `SHARED_SKILLS` in the validator to enforce this.
|
||||||
|
- **Per-repo skills must reflect that repo's reality.** Don't copy infra-specific targets to sso-bridge.
|
||||||
|
|
||||||
|
## Automated Validation
|
||||||
|
|
||||||
|
Every skill must pass the validator (`tests/test_skills.py`). The validator checks:
|
||||||
|
|
||||||
|
1. **Structure** — H1 title, "When to Invoke" section, "Prerequisites" section
|
||||||
|
2. **Commands** — referenced `make <target>` commands exist in Makefile or devx.mak
|
||||||
|
3. **Paths** — referenced file paths exist in the repo
|
||||||
|
4. **Shared skills** — identical content across repos (SHA-256 comparison)
|
||||||
|
5. **No drift** — no references to nonexistent commands or files
|
||||||
|
|
||||||
|
Run the validator:
|
||||||
|
```bash
|
||||||
|
python3 tests/test_skills.py --repo infra --repo sso-bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
## Effectiveness Evaluation
|
||||||
|
|
||||||
|
### Static Checks (automated, CI)
|
||||||
|
|
||||||
|
The validator runs in CI as part of `make pytest-cov`. A failing skill
|
||||||
|
test blocks the PR. This catches:
|
||||||
|
- Missing sections
|
||||||
|
- Invalid commands
|
||||||
|
- Broken file references
|
||||||
|
- Cross-repo drift
|
||||||
|
|
||||||
|
### Runtime Metrics (manual, periodic)
|
||||||
|
|
||||||
|
Track these signals to evaluate skill effectiveness:
|
||||||
|
- **Skill invocation frequency** — how often agents invoke the skill
|
||||||
|
- **Success rate when invoked** — did the skill prevent the mistake it targets?
|
||||||
|
- **Feedback issues** — agents create Gitea issues with `feedback` label when a skill is unclear or wrong
|
||||||
|
- **Mistake recurrence** — if agents still make the mistake the skill targets, the skill needs improvement
|
||||||
|
|
||||||
|
### Retrospective Review
|
||||||
|
|
||||||
|
Periodically (monthly or after major incidents) review skills:
|
||||||
|
1. List all skills and their last-modified dates
|
||||||
|
2. Check for feedback issues tagged `skill-improvement`
|
||||||
|
3. Verify referenced commands still exist (run validator)
|
||||||
|
4. Remove skills that are no longer relevant
|
||||||
|
5. Update skills where mistakes still recur
|
||||||
|
6. Document lessons in this skill's "Common Mistakes" section
|
||||||
|
|
||||||
|
## Creating a New Skill — Checklist
|
||||||
|
|
||||||
|
- [ ] Identify the repeated struggle or non-obvious workflow
|
||||||
|
- [ ] Check no existing skill covers it
|
||||||
|
- [ ] Write the skill following the structure above
|
||||||
|
- [ ] Run `python3 tests/test_skills.py` — must pass
|
||||||
|
- [ ] Run `make pytest-cov` — must pass with 100% coverage
|
||||||
|
- [ ] If shared across repos, copy identical content to each repo
|
||||||
|
- [ ] Add the skill to `SHARED_SKILLS` in the validator if shared
|
||||||
|
- [ ] Create PR, verify CI passes, merge
|
||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.23.0] - 2026-08-28
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Add pre-cache timer, force_pull, and Docker socket options to runner config
|
||||||
|
|
||||||
## [0.22.1] - 2026-08-26
|
## [0.22.1] - 2026-08-26
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
|
|||||||
|
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||||
[](https://www.python.org/downloads/)
|
[](https://www.python.org/downloads/)
|
||||||
|
|
||||||
## Why GRM?
|
## Why GRM?
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,22 @@ gitea_runner_remove_user: true
|
|||||||
gitea_runner_log_level: "info"
|
gitea_runner_log_level: "info"
|
||||||
gitea_runner_container_label: "gitea-runner=true"
|
gitea_runner_container_label: "gitea-runner=true"
|
||||||
gitea_runner_file: ".runner"
|
gitea_runner_file: ".runner"
|
||||||
|
# force_pull: when false (default), the runner reuses locally cached images
|
||||||
|
# instead of pulling on every job. Pre-cached images (via the pre-cache timer
|
||||||
|
# or pre_pull_images task) eliminate registry thundering-herd when all runners
|
||||||
|
# start jobs simultaneously.
|
||||||
|
gitea_runner_force_pull: false
|
||||||
|
# Container options passed to `docker run` for CI job containers.
|
||||||
|
# Mounts the host rootless Docker socket as /run/host-docker.sock so
|
||||||
|
# start_docker.py inside the container can detect and use the host daemon
|
||||||
|
# (full disk, no nested DinD) instead of starting an inner dockerd.
|
||||||
|
gitea_runner_container_options: "-v /run/user/{{ gitea_runner_uid }}/docker.sock:/run/host-docker.sock"
|
||||||
|
# Volumes allowed in CI job containers (validated by the runner against
|
||||||
|
# container.options and job-level volumes). Must include the host Docker
|
||||||
|
# socket mount target.
|
||||||
|
gitea_runner_valid_volumes:
|
||||||
|
- "/run/host-docker.sock"
|
||||||
|
- "/run/user/{{ gitea_runner_uid }}/docker.sock"
|
||||||
|
|
||||||
# Containerd version pinning — Docker 28.x vendors containerd v2.1.x internally.
|
# Containerd version pinning — Docker 28.x vendors containerd v2.1.x internally.
|
||||||
# containerd.io >= 2.3 ships a shim that returns a protobuf BootstrapResult which
|
# containerd.io >= 2.3 ships a shim that returns a protobuf BootstrapResult which
|
||||||
@@ -135,3 +151,11 @@ gitea_runner_docker_ipv6_cidr: "fd00:dead:beef::/48"
|
|||||||
# disk-space prune only removes dangling images, so pre-pulled tagged images persist.
|
# disk-space prune only removes dangling images, so pre-pulled tagged images persist.
|
||||||
# Set to [] to skip pre-pulling. Images are pulled as the runner user via rootless Docker.
|
# Set to [] to skip pre-pulling. Images are pulled as the runner user via rootless Docker.
|
||||||
gitea_runner_pre_pull_images: []
|
gitea_runner_pre_pull_images: []
|
||||||
|
|
||||||
|
# Pre-cache timer: periodically pulls the runner container image so it stays
|
||||||
|
# fresh in the local Docker cache. This prevents thundering-herd registry
|
||||||
|
# timeouts when all runners start CI jobs simultaneously with empty caches.
|
||||||
|
# Runs every 6 hours (aligned with prune schedule). Set to empty string to
|
||||||
|
# disable the timer.
|
||||||
|
gitea_runner_pre_cache_schedule: "*-*-* 00/6:30:00"
|
||||||
|
gitea_runner_pre_cache_images: "{{ gitea_runner_pre_pull_images }}"
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
- name: Include pre-pull images
|
- name: Include pre-pull images
|
||||||
ansible.builtin.include_tasks: pre_pull_images.yml
|
ansible.builtin.include_tasks: pre_pull_images.yml
|
||||||
|
|
||||||
|
- name: Include pre-cache timer
|
||||||
|
ansible.builtin.include_tasks: pre_cache.yml
|
||||||
|
|
||||||
- name: Include integration test
|
- name: Include integration test
|
||||||
ansible.builtin.include_tasks: integration_test.yml
|
ansible.builtin.include_tasks: integration_test.yml
|
||||||
when: not gitea_runner_skip_registration
|
when: not gitea_runner_skip_registration
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
# Periodic timer that pre-pulls CI runner images into the local Docker cache.
|
||||||
|
# Prevents thundering-herd registry timeouts when all runners start jobs
|
||||||
|
# simultaneously with empty/stale caches. Runs every 6 hours (configurable).
|
||||||
|
# The prune timer removes dangling images but NOT tagged ones, so pre-pulled
|
||||||
|
# images persist between runs.
|
||||||
|
|
||||||
|
- name: Create docker-pull-images user service file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-pull-images.service.j2
|
||||||
|
dest: "{{ gitea_runner_home }}/.config/systemd/user/docker-pull-images.service"
|
||||||
|
owner: "{{ gitea_runner_service_user }}"
|
||||||
|
group: "{{ gitea_runner_service_user }}"
|
||||||
|
mode: "0644"
|
||||||
|
register: gitea_runner_pre_cache_service
|
||||||
|
|
||||||
|
- name: Create docker-pull-images user timer file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-pull-images.timer.j2
|
||||||
|
dest: "{{ gitea_runner_home }}/.config/systemd/user/docker-pull-images.timer"
|
||||||
|
owner: "{{ gitea_runner_service_user }}"
|
||||||
|
group: "{{ gitea_runner_service_user }}"
|
||||||
|
mode: "0644"
|
||||||
|
register: gitea_runner_pre_cache_timer
|
||||||
|
|
||||||
|
- name: Reload systemd user daemon for pre-cache timer
|
||||||
|
ansible.builtin.command: systemctl --user daemon-reload
|
||||||
|
become: true
|
||||||
|
become_user: "{{ gitea_runner_service_user }}"
|
||||||
|
environment:
|
||||||
|
XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}"
|
||||||
|
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus"
|
||||||
|
changed_when: true
|
||||||
|
when:
|
||||||
|
- gitea_runner_systemd_available.stat.exists
|
||||||
|
- gitea_runner_docker_rootless_setup
|
||||||
|
- gitea_runner_pre_cache_service is changed or gitea_runner_pre_cache_timer is changed
|
||||||
|
- gitea_runner_pre_cache_schedule | length > 0
|
||||||
|
- gitea_runner_pre_cache_images | length > 0
|
||||||
|
|
||||||
|
- name: Enable and start docker-pull-images user timer
|
||||||
|
ansible.builtin.command: systemctl --user enable --now docker-pull-images.timer
|
||||||
|
become: true
|
||||||
|
become_user: "{{ gitea_runner_service_user }}"
|
||||||
|
environment:
|
||||||
|
XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}"
|
||||||
|
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus"
|
||||||
|
changed_when: true
|
||||||
|
when:
|
||||||
|
- gitea_runner_systemd_available.stat.exists
|
||||||
|
- gitea_runner_docker_rootless_setup
|
||||||
|
- gitea_runner_pre_cache_schedule | length > 0
|
||||||
|
- gitea_runner_pre_cache_images | length > 0
|
||||||
|
|
||||||
|
- name: Disable and stop docker-pull-images timer (no images or schedule)
|
||||||
|
ansible.builtin.command: systemctl --user disable --now docker-pull-images.timer
|
||||||
|
become: true
|
||||||
|
become_user: "{{ gitea_runner_service_user }}"
|
||||||
|
environment:
|
||||||
|
XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}"
|
||||||
|
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ gitea_runner_uid | default(0) }}/bus"
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
when:
|
||||||
|
- gitea_runner_systemd_available.stat.exists
|
||||||
|
- gitea_runner_docker_rootless_setup
|
||||||
|
- gitea_runner_pre_cache_schedule | length == 0 or gitea_runner_pre_cache_images | length == 0
|
||||||
@@ -8,6 +8,15 @@
|
|||||||
#
|
#
|
||||||
# Set gitea_runner_pre_pull_images to a list of image refs to pull, or
|
# Set gitea_runner_pre_pull_images to a list of image refs to pull, or
|
||||||
# empty list to skip pre-pulling.
|
# empty list to skip pre-pulling.
|
||||||
|
#
|
||||||
|
# IMPORTANT: Do NOT use this mechanism for:
|
||||||
|
# - CI runner container images (e.g. ci-full) — these are already
|
||||||
|
# cached by the runner setup task and pulling them here is redundant.
|
||||||
|
# - Images that molecule tests pull themselves — molecule prepare/converge
|
||||||
|
# steps handle their own image pulls; pre-pulling them here wastes time
|
||||||
|
# and disk space.
|
||||||
|
# This mechanism is intended only for images that are needed by the runner
|
||||||
|
# itself but not pulled by any molecule scenario or runner setup step.
|
||||||
|
|
||||||
- name: Pre-pull Docker images for CI runner
|
- name: Pre-pull Docker images for CI runner
|
||||||
ansible.builtin.command: "docker pull {{ item }}"
|
ansible.builtin.command: "docker pull {{ item }}"
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Pre-pull Docker images for CI runner cache
|
||||||
|
After=docker.service
|
||||||
|
Wants=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
Environment=DOCKER_HOST=unix:///run/user/{{ gitea_runner_uid }}/docker.sock
|
||||||
|
Environment=XDG_RUNTIME_DIR=/run/user/{{ gitea_runner_uid }}
|
||||||
|
# Pull each image quietly. docker pull exits 0 if image is already up-to-date,
|
||||||
|
# so this is idempotent. Errors are non-fatal (image may already be cached).
|
||||||
|
{% for image in gitea_runner_pre_cache_images %}
|
||||||
|
ExecStart=/usr/bin/docker pull -q {{ image }}
|
||||||
|
{% endfor %}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Periodic Docker image pre-cache for CI runner
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar={{ gitea_runner_pre_cache_schedule }}
|
||||||
|
Persistent=true
|
||||||
|
RandomizedDelaySec=300
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
@@ -9,3 +9,13 @@ runner:
|
|||||||
container:
|
container:
|
||||||
label: "{{ gitea_runner_container_label }}"
|
label: "{{ gitea_runner_container_label }}"
|
||||||
docker_host: "unix:///run/user/{{ gitea_runner_uid }}/docker.sock"
|
docker_host: "unix:///run/user/{{ gitea_runner_uid }}/docker.sock"
|
||||||
|
force_pull: {{ gitea_runner_force_pull | lower }}
|
||||||
|
{% if gitea_runner_container_options | length > 0 %}
|
||||||
|
options: "{{ gitea_runner_container_options }}"
|
||||||
|
{% endif %}
|
||||||
|
{% if gitea_runner_valid_volumes | length > 0 %}
|
||||||
|
valid_volumes:
|
||||||
|
{% for volume in gitea_runner_valid_volumes %}
|
||||||
|
- "{{ volume }}"
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|||||||
+6
-6
@@ -8,12 +8,12 @@ Each runner runs in an isolated **rootless Docker** environment under a dedicate
|
|||||||
|
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/src/branch/master/LICENSE)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/wiki)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/actions)
|
||||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
[](https://git.oblachno.oblachno.fyi/oblachno-oss/grm/releases)
|
||||||
[](https://www.python.org/downloads/)
|
[](https://www.python.org/downloads/)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# GRM-162: Add pre-cache timer, force_pull, and Docker socket options to runner config
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
CI containers were not using the host's rootless Docker daemon, leading to
|
||||||
|
"no space left on device" errors. The runner config template was missing
|
||||||
|
`force_pull`, `options` (host Docker socket mount), and `valid_volumes`
|
||||||
|
fields. Additionally, no pre-cache timer existed to prevent thundering-herd
|
||||||
|
registry timeouts when all runners pull images simultaneously.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
REQ-1: Add `force_pull: false` to runner config template (explicit default
|
||||||
|
so the runner reuses locally cached images instead of pulling on every job)
|
||||||
|
REQ-2: Add `options` field to mount host rootless Docker socket as
|
||||||
|
`/run/host-docker.sock` so `start_docker.py` inside CI containers can detect
|
||||||
|
and use the host daemon (full disk, no nested DinD)
|
||||||
|
REQ-3: Add `valid_volumes` list for the socket mount targets (validated by
|
||||||
|
the runner against `container.options` and job-level volumes)
|
||||||
|
REQ-4: Add `pre_cache.yml` task with a systemd user timer that pre-pulls CI
|
||||||
|
images every 6 hours (configurable via `gitea_runner_pre_cache_schedule`)
|
||||||
|
REQ-5: Add `docker-pull-images.service.j2` and `docker-pull-images.timer.j2`
|
||||||
|
templates for the pre-cache timer
|
||||||
|
REQ-6: Timer is disabled when `gitea_runner_pre_cache_schedule` is empty or
|
||||||
|
`gitea_runner_pre_cache_images` is empty (graceful degradation)
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- `make lint-ci` passes (ansible-lint on new task/template files)
|
||||||
|
- `make molecule` converges successfully with the new pre-cache tasks
|
||||||
|
- Verify the runner config template renders correctly with and without
|
||||||
|
container options/valid_volumes
|
||||||
|
|
||||||
|
## Deploy Plan
|
||||||
|
- Merge to master → post-merge auto-publishes package
|
||||||
|
- Infra dependency PR auto-created to bump pinned grm version
|
||||||
|
- Runners pick up the new config on next `make setup` or ansible apply
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
- Revert the merge commit
|
||||||
|
- Set `gitea_runner_pre_cache_schedule: ""` to disable the timer without
|
||||||
|
reverting
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [x] REQ-1: `force_pull: false` in runner config template
|
||||||
|
- [x] REQ-2: `options` field mounts host Docker socket as `/run/host-docker.sock`
|
||||||
|
- [x] REQ-3: `valid_volumes` list includes both socket mount targets
|
||||||
|
- [x] REQ-4: `pre_cache.yml` task creates and manages systemd user timer
|
||||||
|
- [x] REQ-5: Service and timer templates created
|
||||||
|
- [x] REQ-6: Timer disabled gracefully when schedule or images empty
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# GRM-172: Audit and document pre-pull image usage guidelines
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
The grm repo contains a runner-level `pre_pull_images.yml` task file that
|
||||||
|
pre-pulls Docker images to avoid repeated pulls on every CI run. However,
|
||||||
|
there was no audit confirming that molecule `prepare.yml` files are not
|
||||||
|
also redundantly pre-pulling images that the runner setup already caches.
|
||||||
|
Wasteful pre-pulling wastes CI time and disk space.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Audit all molecule `prepare.yml` files in the grm repo for pre-pull tasks.
|
||||||
|
The audit found NO molecule prepare.yml files contain pre-pull tasks, so no
|
||||||
|
code removal is needed. Document the audit findings in a spec and add a
|
||||||
|
comment to the runner-level `pre_pull_images.yml` task file clarifying that
|
||||||
|
it should not be used for images that molecule tests pull themselves (to
|
||||||
|
avoid redundant pulls).
|
||||||
|
|
||||||
|
REQ-1: Audit all molecule prepare.yml files for pre-pull tasks and confirm none exist
|
||||||
|
REQ-2: Add documentation comment to pre_pull_images.yml stating it should not be used for CI runner container images (already cached by runner setup) or images molecule tests pull themselves
|
||||||
|
REQ-3: Confirm gitea_runner_pre_pull_images default remains empty ([]) which is correct
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- Grep all molecule prepare.yml files for pre-pull patterns confirms zero matches
|
||||||
|
- Verify pre_pull_images.yml comment is present and accurate
|
||||||
|
- Verify gitea_runner_pre_pull_images default is [] in defaults/main.yml
|
||||||
|
- Run make lint-ci to confirm no lint regressions
|
||||||
|
|
||||||
|
## Deploy Plan
|
||||||
|
- Merge to master via auto-merge workflow
|
||||||
|
- No runtime changes; documentation-only
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
- Revert the merge commit; comments are removed, no functional impact
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [x] REQ-1: No molecule prepare.yml files in the grm repo contain pre-pull tasks (audit confirmed via grep)
|
||||||
|
- [x] REQ-2: pre_pull_images.yml contains a comment documenting it should not be used for CI runner container images or images molecule tests pull themselves
|
||||||
|
- [x] REQ-3: gitea_runner_pre_pull_images default remains empty ([]) in defaults/main.yml
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# GRM-173: Add dependency-graph, deployment-coordination, and skill-creation skills
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
Agents working across the oblachno ecosystem lack shared, written context
|
||||||
|
for three recurring struggles: (1) knowing which repo produces what and
|
||||||
|
the correct order for cross-repo changes, (2) coordinating grm releases
|
||||||
|
with the downstream infra dependency PR, and (3) creating and validating
|
||||||
|
new Devin skills consistently. Without these skills, agents repeatedly
|
||||||
|
make mistakes such as deploying infra before the grm dependency PR is
|
||||||
|
merged, or writing skills that fail the validator.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Add three skill files under `.devin/skills/`. Two are shared skills
|
||||||
|
(`dependency-graph`, `skill-creation`) that must be identical across
|
||||||
|
repos; one is grm-specific (`deployment-coordination`). All three
|
||||||
|
follow the standard skill structure (H1 title, When to Invoke,
|
||||||
|
Prerequisites, core content) and reference real make targets, file
|
||||||
|
paths, and API endpoints.
|
||||||
|
|
||||||
|
REQ-1: Add `.devin/skills/dependency-graph/SKILL.md` — shared skill mapping the oblachno ecosystem (repos, produces/consumers, dependency chain, correct change order, state verification)
|
||||||
|
REQ-2: Add `.devin/skills/deployment-coordination/SKILL.md` — grm-specific skill covering release flow, downstream consumer, coordinating a grm change, and common mistakes
|
||||||
|
REQ-3: Add `.devin/skills/skill-creation/SKILL.md` — shared skill for creating, validating, and maintaining skills (structure, quality standards, scope rules, automated validation, checklist)
|
||||||
|
|
||||||
|
## Files Affected
|
||||||
|
- `.devin/skills/dependency-graph/SKILL.md` (new)
|
||||||
|
- `.devin/skills/deployment-coordination/SKILL.md` (new)
|
||||||
|
- `.devin/skills/skill-creation/SKILL.md` (new)
|
||||||
|
- `docs/specs/GRM-173.md` (new)
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- Verify all three SKILL.md files follow the required structure (H1, When to Invoke, Prerequisites)
|
||||||
|
- Verify referenced make targets and file paths are accurate
|
||||||
|
- Run `make pytest-cov` to confirm no test regressions (skills are docs-only, no code changes)
|
||||||
|
- Confirm shared skills (`dependency-graph`, `skill-creation`) are ready for cross-repo sync
|
||||||
|
|
||||||
|
## Deploy Plan
|
||||||
|
- Merge to master via auto-merge workflow
|
||||||
|
- No runtime changes; documentation-only (`.devin/**` is infrastructure path, no release triggered)
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
- Revert the merge commit; skill files are removed, no functional impact
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [x] REQ-1: `.devin/skills/dependency-graph/SKILL.md` exists with ecosystem map, dependency chain, correct change order, and state verification sections
|
||||||
|
- [x] REQ-2: `.devin/skills/deployment-coordination/SKILL.md` exists with release flow, downstream consumer table, coordination steps, and common mistakes
|
||||||
|
- [x] REQ-3: `.devin/skills/skill-creation/SKILL.md` exists with skill structure template, quality standards, scope rules, automated validation, and creation checklist
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
"""Gitea Runner Manager — lean CLI for managing Gitea Actions runners."""
|
"""Gitea Runner Manager — lean CLI for managing Gitea Actions runners."""
|
||||||
|
|
||||||
__version__ = "0.22.1"
|
__version__ = "0.23.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user