Compare commits

...
Sign in to create a new pull request.

30 commits
main ... dev

Author SHA1 Message Date
Snider
6ec9fa13fc fix(install): use latest release instead of hardcoded version
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Free Tier Security Scanners / semgrep (push) Waiting to run
Free Tier Security Scanners / trivy (push) Waiting to run
Free Tier Security Scanners / gitleaks (push) Waiting to run
Free Tier Security Scanners / osv-scanner (push) Waiting to run
Free Tier Security Scanners / checkov (push) Waiting to run
Free Tier Security Scanners / aggregate-findings (push) Blocked by required conditions
Bootstrap from Template / bootstrap (push) Waiting to run
Test Setup Scripts / Linux (Ubuntu) (push) Waiting to run
Test Setup Scripts / macOS (push) Waiting to run
Test Setup Scripts / Windows (push) Waiting to run
Test Setup Scripts / All Platforms (push) Blocked by required conditions
- install-core.sh: Auto-detect latest release via gh/curl (was hardcoded v0.1.0)
- install-core.ps1: Add Get-LatestVersion for build-from-source path
- install-deps.sh: Fix bash 3 compatibility (${var,,} → tr)
- README.md: Fix command (core health → core dev health)
- Fix CRLF line endings in shell scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 02:36:18 +00:00
Snider
ec2e1c9865 fix(install): use latest release instead of hardcoded version
- Download from /releases/latest/download/ URL
- Remove hardcoded version variable
- Simplify clone to use default branch

Related to host-uk/core#37

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:21:46 +00:00
Snider
670fad9bbf docs: update TODO with auto-labeling progress
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:38:09 +00:00
Snider
1d762222e7 feat(github): add complexity labels with heuristic detection
- Add complexity dropdown to feature request template
- Auto-detect complexity from dropdown selection
- Heuristic fallback based on: checklist count, code blocks,
  section headers, file references, and keywords

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:33:50 +00:00
Snider
2263ba7680 feat(github): add auto-labeler workflow for issues
Labels issues based on title prefixes and content keywords:
- Type labels: bug, enhancement, documentation
- Project labels: core-cli, core-php, workstation
- Priority and agentic labels

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:23:47 +00:00
Snider
5deaf4fc7a feat(repos): add core-claude to package registry
Claude Code plugin with skills for PHP and Go agent workflows.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:24:51 +00:00
Snider
a74f616fd7 feat(skills): add autonomous Go agent skill
Adds /go-agent skill for continuous Go development:
- Finds open issues in host-uk/core repo
- Creates branches, implements solutions, writes tests
- Uses Task runner (task test, task lint, etc.)
- Handles CodeRabbit reviews automatically
- Merges when approved
- Loops to pick up next task

Go-specific features:
- Error handling patterns with errors.E
- Test naming conventions (_Good, _Bad, _Ugly)
- i18n string management
- Package reference for core CLI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:17:09 +00:00
Snider
6440b8fe42 feat(skills): add autonomous PHP agent skill
Adds /php-agent skill for continuous PHP development:
- Finds open issues across host-uk PHP repos
- Creates branches, implements solutions, writes tests
- Handles CodeRabbit reviews automatically
- Merges when approved
- Loops to pick up next task

Includes:
- php-agent.md skill definition with full workflow
- Updated plugin.json registration
- Extended permissions in settings.local.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:15:05 +00:00
Snider
04bd1b3d08 feat(config): add GitHub configuration for setup command
Adds .core/github.yaml with org-standard labels, webhook templates,
branch protection rules, and security settings for use with
`core setup github`.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 02:37:49 +00:00
Snider
9c9e79587b chore(ide): update dictionary word order
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:42:44 +00:00
Snider
07ce689a8c feat(github): enable free GitHub features
- dependabot.yml: automated updates for GitHub Actions and Go modules
- CODEOWNERS: auto-assign reviewers by path
- SECURITY.md: vulnerability reporting policy
- ISSUE_TEMPLATE/: structured bug reports and feature requests
- PULL_REQUEST_TEMPLATE.md: PR checklist

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:29:52 +00:00
Snider
c99101a29d feat(ide): add shared JetBrains/PhpStorm configuration
- Code style: PSR-12 for PHP, 2-space indent for JS/TS/YAML
- Inspection profile: Laravel-friendly, reduced noise in vendor
- Run configurations: Composer test/lint, PHPStan, clone-repos
- Scopes: Packages, Vendor, Tests for focused searches
- Dictionary: Project-specific terms (agentic, livewire, etc.)
- PHP 8.4 language level, Laravel Idea multimodule support
- File watcher: Pint auto-format (disabled by default)
- Excludes: vendor/ and node_modules/ for faster indexing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:22:33 +00:00
Snider
9a52fd937a fix(windows): improve PowerShell installer and add clone script
- Fix return value leakage in install-core.ps1 (suppressed with $null)
- Fix ACL -bor compatibility across PowerShell versions
- Handle unsigned/lightweight git tags in GPG verification
- Skip GPG verification for branch builds (main)
- Add explicit GOOS=windows for Go build
- Detect Windows syscall build errors with helpful message
- Add clone-repos.ps1 as Windows alternative to `core setup`
- Update CLAUDE.md with Windows-specific setup instructions

Closes #56 workaround documented

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:17:10 +00:00
Snider
621438a876 docs: update TODO with container image progress
- Added container images section (core-images)
- Tracked dual-registry workflow (GHCR + Docker Hub)
- Added core CLI issue #50 (linuxkit flags)
- Added DOCKERHUB_TOKEN rotation reminder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:22:22 +00:00
Snider
438ad7bd65 fix: align container image naming convention
Use ghcr.io/host-uk/core-images:{tag} format where tag is the
image variant (developer, server-php) rather than path-based naming.

See: https://github.com/host-uk/core-images/issues/1

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:10:44 +00:00
Snider
63079ed187 feat: add developer container config with packages/ mount
- docker-compose.yml for standalone Docker usage
- .devcontainer/devcontainer.json for VS Code/Cursor
- Mounts packages/ as /workspace in container
- Persists home directory with named volume
- SSH and gitconfig mounted read-only

Uses ghcr.io/host-uk/core-images/developer:latest

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:58:09 +00:00
Snider
dff9bcb43c docs: mark PHP workflows complete 2026-01-31 22:50:27 +00:00
Snider
f1cb5c5c93 docs: add session TODO summary 2026-01-31 22:48:55 +00:00
Snider
6d34cbe33c docs: add contributor onboarding for distributed compute network
Host UK CIC mission: aggregate free tier compute to benefit OSS commons

Added:
- CONTRIBUTING.md: 5-minute contributor onboarding guide
- scripts/contribute.sh: One-command setup for new contributors
- Updated free-tier-services.md: Mission context, economics explained

The model:
- 100 contributors × free tiers = enterprise-scale compute
- core monitor aggregates findings from all sources
- Tasks routed to Host UK packages AND unfunded OSS projects
- LLMs learned from OSS, we give back

Who pays: Microsoft, Google, Groq (marketing budgets)
Who benefits: Open source commons

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:44:17 +00:00
Snider
9c10ff9b1c feat: add comprehensive free tier integrations
AI Services (contributor's fork pays):
- Groq: 14,400 req/day (Llama 3.3 70B)
- Mistral: 1M tokens/month
- Cohere: 1000 req/month (classification)
- Cloudflare AI: 10K neurons/day
- Gemini: 1500 req/day (existing)

Security Scanners (100% free, no keys):
- Semgrep: SAST
- Trivy: Container/IaC vulns
- Gitleaks: Secret detection
- OSV-Scanner: Google vuln DB
- Checkov: IaC security

All results:
- Upload to GitHub Security tab (SARIF)
- Create artifacts for core CLI to consume
- Feed into Agentic task queue

Doc: free-tier-services.md lists 50+ free services

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:36:27 +00:00
Snider
a78ef46133 feat: add AI worker workflows (Gemini + Jules)
Distributed AI compute using contributor's free tiers:

Gemini 2.0 Flash (ai-worker.yml):
- 1500 req/day free from Google
- Code review, security scan, bug detection
- Contributor sets GEMINI_API_KEY in fork secrets

Jules/Copilot (jules-dispatch.yml):
- Triggered by @jules or /jules comments
- Creates PRs to fix issues automatically
- Uses contributor's Copilot allowance (free for OSS)

Documentation (doc/free-tier-compute.md):
- Setup guide for all free tiers
- Compute distribution model diagram
- Donor fleet instructions

Innocent strategy: Jules commits fixes to contributor's fork 😇

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:30:38 +00:00
Snider
c03c49a539 ci: add fork-based compute workflows
Strategy: Heavy analysis runs on contributor's GitHub Actions allowance
Microsoft/GitHub subsidizes the compute through free tiers

Workflows:
- contributor-ci.yml: Full CI runs on fork (contributor pays)
- fork-ai-triage.yml: AI analysis, labeling, security scan (fork pays)
- fork-pr-analysis.yml: Upstream just verifies fork CI passed

Benefits:
- Unlimited scale via contributor free tiers
- AI/Copilot features use their allowance
- We only pay for lightweight verification
- Forks inherit these workflows automatically

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:27:08 +00:00
Snider
7c4e9222ef feat: add template bootstrap workflow and setup guide
When creating a new repo from this template:
- template-bootstrap.yml runs on first push
- Creates standard labels (agent:*, priority:*, type:*)
- Enables security features (Dependabot, vuln alerts)
- Creates setup checklist issue
- TEMPLATE_SETUP.md guides customization

Files to customize: repos.yaml, CLAUDE.md, README.md
Delete TEMPLATE_SETUP.md when done.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 22:24:05 +00:00
Snider
42d495a7e8 chore: add CodeRabbit configuration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:41:44 +00:00
Snider
d6d4ddb15b ci: add security scanning workflow templates
Templates for repos to enable language-specific security scanning:
- security-php.yml: PHPStan + Semgrep SAST
- security-shell.yml: ShellCheck for bash scripts
- security-docker.yml: Hadolint for Dockerfiles

CodeQL default setup now enabled across all public repos for:
- Go, JavaScript/TypeScript (core, core-gui, build)
- JavaScript/TypeScript (core-admin, core-api, core-mcp, etc.)
- Actions workflow scanning (core-php, core-tenant, etc.)
- Python (ansible-*, docker-server-blockchain)
- C# (btcpayserver-docker)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 21:35:16 +00:00
Snider
c6139214eb fix: remove npm cache requirement from docs workflow 2026-01-31 20:40:00 +00:00
Snider
97aab0fcca docs: add VitePress documentation with GitHub Pages deployment
- VitePress config with canonical URLs to core.help
- Developer preview banner linking to main docs
- Documentation pages: quick-start, commands, core-folder, repos-yaml
- GitHub Actions workflow for Pages deployment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:28:07 +00:00
Snider
8a921dfb2d ci: add CodeQL security scanning 2026-01-31 20:04:32 +00:00
Snider
b1aada9b0e docs: add project scope to gh auth setup
- Add read:project,project scopes to gh auth in install scripts
- Update troubleshooting docs for missing scopes
- Enable GitHub Projects access for workspace management

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:57:30 +00:00
Snider
99897636a1 ci: add cross-platform setup test workflow
- Add GitHub Actions workflow to test install scripts on Linux, macOS, Windows
- Runs weekly to catch upstream package changes
- Update install-deps.sh to configure gh with workflow scope
- Document workflow scope in README.md and CLAUDE.md troubleshooting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:05:52 +00:00
76 changed files with 4537 additions and 42 deletions

View file

@ -0,0 +1,66 @@
{
"permissions": {
"allow": [
"Bash(where git go gh php composer node pnpm)",
"Bash(go version:*)",
"Bash(git --version)",
"Bash(gh --version:*)",
"Bash(powershell -ExecutionPolicy Bypass -File scripts/install-core.ps1:*)",
"Bash(git ls-remote:*)",
"Bash(C:/Users/snide/AppData/Local/Programs/core/core.exe --help)",
"Bash(powershell -Command \"cd packages/core-php; composer install\")",
"Bash(powershell -Command:*)",
"Bash(gh issue list:*)",
"Bash(git add:*)",
"Bash(gh issue view:*)",
"Bash(core doctor)",
"Bash(core dev status:*)",
"Bash(core pkg list:*)",
"Bash(core php test --help:*)",
"Bash(core dev health:*)",
"Bash(core php test)",
"Bash(git push:*)",
"Bash(go build:*)",
"Bash(gh issue create:*)",
"Bash(git checkout:*)",
"Bash(git stash:*)",
"Bash(gh api:*)",
"Bash(gh pr checks:*)",
"Bash(git fetch:*)",
"Bash(git rebase:*)",
"Bash(git branch:*)",
"Bash(gh pr view:*)",
"Bash(git pull:*)",
"Bash(gh run list:*)",
"Bash(gh run view:*)",
"Bash(gh search issues:*)",
"Bash(gh search prs:*)",
"Bash(gh issue comment:*)",
"Bash(gh issue edit:*)",
"Bash(gh issue close:*)",
"Bash(gh pr create:*)",
"Bash(gh pr merge:*)",
"Bash(composer test:*)",
"Bash(composer lint:*)",
"Bash(composer analyse:*)",
"Bash(composer install:*)",
"Bash(git commit:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git rev-parse:*)",
"Bash(go test:*)",
"Bash(go build:*)",
"Bash(go vet:*)",
"Bash(go mod tidy:*)",
"Bash(golangci-lint:*)",
"Bash(task test:*)",
"Bash(task cov:*)",
"Bash(task lint:*)",
"Bash(task fmt:*)",
"Bash(task qa:*)",
"Bash(task cli:build:*)",
"Bash(task mod:tidy:*)"
]
}
}

13
.coderabbit.yaml Normal file
View file

@ -0,0 +1,13 @@
# CodeRabbit Configuration
# Inherits from: https://github.com/host-uk/coderabbit/.coderabbit.yaml
reviews:
review_status: false
path_instructions:
- path: "scripts/**"
instructions: "Setup scripts - ensure cross-platform compatibility (macOS, Linux, Windows)"
- path: "doc/**"
instructions: "Documentation - check for accuracy and British English spelling"
- path: ".github/**"
instructions: "GitHub config - validate workflow syntax and action versions"

157
.core/github.yaml Normal file
View file

@ -0,0 +1,157 @@
# GitHub repository configuration for Host UK organisation.
# Used by: core setup github
#
# Environment variables can be referenced using ${VAR} or ${VAR:-default} syntax.
version: 1
# Organisation-standard labels
labels:
# Priority labels
- name: "priority:critical"
color: "b60205"
description: "Must be fixed immediately"
- name: "priority:high"
color: "d93f0b"
description: "Should be fixed soon"
- name: "priority:medium"
color: "fbca04"
description: "Normal priority"
- name: "priority:low"
color: "0e8a16"
description: "Nice to have"
# Type labels
- name: "type:bug"
color: "d73a4a"
description: "Something isn't working"
- name: "type:feature"
color: "a2eeef"
description: "New feature or request"
- name: "type:enhancement"
color: "84b6eb"
description: "Improvement to existing feature"
- name: "type:docs"
color: "0075ca"
description: "Documentation improvements"
- name: "type:refactor"
color: "d4c5f9"
description: "Code refactoring"
- name: "type:test"
color: "bfd4f2"
description: "Test improvements"
- name: "type:chore"
color: "fef2c0"
description: "Maintenance tasks"
- name: "type:security"
color: "ee0701"
description: "Security-related issue"
# Status labels
- name: "status:blocked"
color: "b60205"
description: "Blocked by another issue or external factor"
- name: "status:in-progress"
color: "fbca04"
description: "Currently being worked on"
- name: "status:review"
color: "6f42c1"
description: "Ready for review"
- name: "status:ready"
color: "0e8a16"
description: "Ready for development"
# Agent labels (for AI-assisted development)
- name: "agent:ready"
color: "00ff00"
description: "Task ready for AI agent pickup"
- name: "agent:assigned"
color: "1d76db"
description: "Task assigned to AI agent"
- name: "agent:blocked"
color: "e99695"
description: "Agent needs human input"
- name: "agent:completed"
color: "0e8a16"
description: "Agent completed the task"
# Scope labels
- name: "scope:api"
color: "c5def5"
description: "API changes"
- name: "scope:ui"
color: "bfdadc"
description: "User interface changes"
- name: "scope:db"
color: "d4c5f9"
description: "Database changes"
- name: "scope:infra"
color: "f9d0c4"
description: "Infrastructure changes"
- name: "scope:deps"
color: "fef2c0"
description: "Dependency updates"
# Workflow labels
- name: "breaking"
color: "b60205"
description: "Contains breaking changes"
- name: "good first issue"
color: "7057ff"
description: "Good for newcomers"
- name: "help wanted"
color: "008672"
description: "Extra attention is needed"
- name: "wontfix"
color: "ffffff"
description: "This will not be worked on"
- name: "duplicate"
color: "cfd3d7"
description: "This issue or pull request already exists"
# Webhooks (optional - set env vars to enable)
webhooks:
discord-push:
url: ${DISCORD_WEBHOOK_PUSH:-}
events:
- push
- release
content_type: json
discord-issues:
url: ${DISCORD_WEBHOOK_ISSUES:-}
events:
- issues
- issue_comment
- pull_request
- pull_request_review
content_type: json
# Branch protection rules
branch_protection:
- branch: main
required_reviews: 1
dismiss_stale: true
require_code_owner_reviews: false
enforce_admins: false
require_linear_history: false
allow_force_pushes: false
allow_deletions: false
require_conversation_resolution: true
- branch: dev
required_reviews: 1
dismiss_stale: true
require_code_owner_reviews: false
enforce_admins: false
require_linear_history: false
allow_force_pushes: false
allow_deletions: false
require_conversation_resolution: false
# Security settings
security:
dependabot_alerts: true
dependabot_security_updates: true
secret_scanning: true
push_protection: true

View file

@ -19,6 +19,16 @@
"name": "package-status",
"file": "skills/package-status.md",
"description": "Show status of all packages in the workspace"
},
{
"name": "php-agent",
"file": "skills/php-agent.md",
"description": "Autonomous PHP development agent - picks up issues, implements, handles reviews, merges"
},
{
"name": "go-agent",
"file": "skills/go-agent.md",
"description": "Autonomous Go development agent - picks up issues, implements, handles reviews, merges"
}
],

View file

@ -0,0 +1,415 @@
# Go Agent Skill
You are an autonomous Go development agent working on the Host UK Go projects (primarily the `core` CLI). You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
## Workflow Loop
This skill runs as a continuous loop:
```
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
2. FIND ISSUE → Pick a Go issue from host-uk org
3. IMPLEMENT → Create branch, code, test, push
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
5. MERGE → Merge when approved
6. REPEAT → Start next task
```
## State Management
Track your work with these variables:
- `PENDING_PRS`: PRs waiting for CodeRabbit review
- `CURRENT_ISSUE`: Issue currently being worked on
- `CURRENT_BRANCH`: Branch for current work
---
## Step 1: Check Pending PRs
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
```bash
# List your open PRs in the core repo
gh pr list --repo host-uk/core --author=@me --state=open --json number,title,headRefName,url
# For each PR, check CodeRabbit status
gh api repos/host-uk/core/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
```
### If CodeRabbit review is complete:
- **Success (no issues)**: Merge the PR
- **Has comments**: Fix the issues, commit, push, continue to next task
```bash
# Check for new reviews
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
# If actionable comments, read and fix them
# Then commit and push:
git add -A && git commit -m "fix: address CodeRabbit feedback
Co-Authored-By: Claude <noreply@anthropic.com>"
git push
```
### Merging PRs
```bash
# When CodeRabbit approves (status: success), merge without admin
gh pr merge {pr_number} --squash --repo host-uk/core
```
---
## Step 2: Find an Issue
Search for Go issues in the Host UK organization.
```bash
# Find open issues labeled for Go
gh search issues --owner=host-uk --state=open --label="lang:go" --json number,title,repository,url --limit=10
# Or list issues in the core repo directly
gh issue list --repo host-uk/core --state=open --json number,title,labels,body --limit=20
# Check for agent-ready issues
gh issue list --repo host-uk/core --state=open --label="agent:ready" --json number,title,body
```
### Issue Selection Criteria
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
2. **Dependencies**: Check if issue depends on other incomplete work
3. **Scope**: Prefer issues that can be completed in one session
4. **Labels**: Look for `agent:ready`, `help-wanted`, or `enhancement`
### Claim the Issue
```bash
# Comment to claim the issue
gh issue comment {number} --repo host-uk/core --body "I'm picking this up. Starting work now."
# Assign yourself (if you have permission)
gh issue edit {number} --repo host-uk/core --add-assignee @me
```
---
## Step 3: Implement the Solution
### Setup Branch
```bash
# Navigate to the core package
cd packages/core
# Ensure you're on dev and up to date
git checkout dev && git pull
# Create feature branch
git checkout -b feature/issue-{number}-{short-description}
```
### Development Workflow
1. **Read the code** - Understand the package structure
2. **Write tests first** - TDD approach when possible
3. **Implement the solution** - Follow Go best practices
4. **Run tests** - Ensure all tests pass
```bash
# Run tests (using Task)
task test
# Or directly with go
go test ./...
# Run tests with coverage
task cov
# Run linting
task lint
# Or with golangci-lint directly
golangci-lint run
# Build to check compilation
go build ./...
```
### Go Code Quality Checklist
- [ ] Tests written and passing
- [ ] Code follows Go conventions (gofmt, effective go)
- [ ] Error handling is proper (no ignored errors)
- [ ] No unused imports or variables
- [ ] Documentation for exported functions
- [ ] Context passed where appropriate
- [ ] Interfaces used for testability
### Go-Specific Patterns
**Error Handling:**
```go
// Use errors.E for contextual errors
return errors.E("service.method", "what failed", err)
// Or errors.Wrap for wrapping
return errors.Wrap(err, "service.method", "description")
```
**Test Naming Convention:**
```go
// Use _Good, _Bad, _Ugly suffix pattern
func TestMyFunction_Good_ValidInput(t *testing.T) { ... }
func TestMyFunction_Bad_InvalidInput(t *testing.T) { ... }
func TestMyFunction_Ugly_PanicCase(t *testing.T) { ... }
```
**i18n Strings:**
```go
// Use i18n package for user-facing strings
i18n.T("cmd.mycommand.description")
i18n.Label("status")
```
### Creating Sub-Issues
If the issue reveals additional work needed:
```bash
# Create a follow-up issue
gh issue create --repo host-uk/core \
--title "Follow-up: {description}" \
--body "Discovered while working on #{original_issue}
## Context
{explain what was found}
## Proposed Solution
{describe the approach}
## References
- Parent issue: #{original_issue}" \
--label "lang:go,follow-up"
```
---
## Step 4: Push and Create PR
```bash
# Stage and commit
git add -A
git commit -m "feat({pkg}): {description}
{longer description if needed}
Closes #{issue_number}
Co-Authored-By: Claude <noreply@anthropic.com>"
# Push
git push -u origin feature/issue-{number}-{short-description}
# Create PR
gh pr create --repo host-uk/core \
--title "feat({pkg}): {description}" \
--body "$(cat <<'EOF'
## Summary
{Brief description of changes}
## Changes
- {Change 1}
- {Change 2}
## Test Plan
- [ ] Unit tests added/updated
- [ ] `task test` passes
- [ ] `task lint` passes
- [ ] Manual testing completed
Closes #{issue_number}
---
Generated with Claude Code
EOF
)"
```
---
## Step 5: Handle CodeRabbit Review
After pushing, CodeRabbit will automatically review. Track PR status:
```bash
# Check CodeRabbit status on latest commit
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
```
### While Waiting
Instead of blocking, **start working on the next issue** (go to Step 2).
### When Review Arrives
```bash
# Check the review
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq '.[-1]'
# If "Actionable comments posted: N", fix them:
# 1. Read each comment
# 2. Make the fix
# 3. Commit with clear message
# 4. Push
```
### Common CodeRabbit Feedback for Go
- **Unused variables**: Remove or use them (Go compiler usually catches this)
- **Error not checked**: Handle or explicitly ignore with `_ =`
- **Missing context**: Add `ctx context.Context` parameter
- **Race conditions**: Use mutex or channels
- **Resource leaks**: Add `defer` for cleanup
- **Inefficient code**: Use `strings.Builder`, avoid allocations in loops
- **Missing documentation**: Add doc comments for exported symbols
---
## Step 6: Merge and Close
When CodeRabbit status shows "Review completed" with state "success":
```bash
# Merge the PR (squash merge)
gh pr merge {pr_number} --squash --repo host-uk/core
# The issue will auto-close if "Closes #N" was in PR body
# Otherwise, close manually:
gh issue close {number} --repo host-uk/core
```
---
## Step 7: Restart Loop
After merging:
1. Remove PR from `PENDING_PRS`
2. Check remaining pending PRs for reviews
3. Pick up next issue
4. **Restart this skill** to continue the loop
```
>>> LOOP COMPLETE - Restart /go-agent to continue working <<<
```
---
## Go Packages Reference (core CLI)
| Package | Purpose |
|---------|---------|
| `pkg/cli` | Command framework, styles, output |
| `pkg/errors` | Error handling with context |
| `pkg/i18n` | Internationalization |
| `pkg/qa` | QA commands (watch, review) |
| `pkg/setup` | Setup commands (github, bootstrap) |
| `pkg/dev` | Multi-repo dev workflow |
| `pkg/go` | Go tooling commands |
| `pkg/php` | PHP tooling commands |
| `pkg/build` | Build system |
| `pkg/release` | Release management |
| `pkg/sdk` | SDK generators |
| `pkg/container` | Container/VM management |
| `pkg/agentic` | Agent orchestration |
| `pkg/framework/core` | Core DI framework |
---
## Task Commands Reference
```bash
# Testing
task test # Run all tests
task test:verbose # Verbose output
task test:run -- Name # Run specific test
task cov # Coverage report
# Code Quality
task fmt # Format code
task lint # Run linter
task qa # Full QA (fmt, vet, lint, test)
task qa:quick # Quick QA (no tests)
# Building
task cli:build # Build CLI to ./bin/core
task cli:install # Install to system
# Other
task mod:tidy # go mod tidy
task review # CodeRabbit review
```
---
## Troubleshooting
### CodeRabbit Not Reviewing
```bash
# Check commit status
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status
# Check if webhooks are configured
gh api repos/host-uk/core/hooks
```
### Tests Failing
```bash
# Run with verbose output
go test -v ./...
# Run specific test
go test -run TestName ./pkg/...
# Run with race detector
go test -race ./...
```
### Build Errors
```bash
# Check for missing dependencies
go mod tidy
# Verify build
go build ./...
# Check for vet issues
go vet ./...
```
### Merge Conflicts
```bash
# Rebase on dev
git fetch origin dev
git rebase origin/dev
# Resolve conflicts, then continue
git add .
git rebase --continue
git push --force-with-lease
```
---
## Best Practices
1. **One issue per PR** - Keep changes focused
2. **Small commits** - Easier to review and revert
3. **Descriptive messages** - Help future maintainers
4. **Test coverage** - Don't decrease coverage
5. **Documentation** - Update if behavior changes
6. **Error context** - Use errors.E with service.method prefix
7. **i18n strings** - Add to en_GB.json for user-facing text
## Labels Reference
- `lang:go` - Go code changes
- `agent:ready` - Ready for AI agent pickup
- `good-first-issue` - Simple, well-defined tasks
- `priority:high` - Should be addressed soon
- `follow-up` - Created from another issue
- `needs:review` - Awaiting human review
- `bug` - Something isn't working
- `enhancement` - New feature or improvement

View file

@ -0,0 +1,329 @@
# PHP Agent Skill
You are an autonomous PHP development agent working on the Host UK Laravel packages. You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
## Workflow Loop
This skill runs as a continuous loop:
```
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
2. FIND ISSUE → Pick a PHP issue from host-uk org
3. IMPLEMENT → Create branch, code, test, push
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
5. MERGE → Merge when approved
6. REPEAT → Start next task
```
## State Management
Track your work with these variables:
- `PENDING_PRS`: PRs waiting for CodeRabbit review
- `CURRENT_ISSUE`: Issue currently being worked on
- `CURRENT_BRANCH`: Branch for current work
---
## Step 1: Check Pending PRs
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
```bash
# List your open PRs across host-uk org
gh search prs --author=@me --state=open --owner=host-uk --json number,title,repository,url
# For each PR, check CodeRabbit status
gh api repos/host-uk/{repo}/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
```
### If CodeRabbit review is complete:
- **Success (no issues)**: Merge the PR
- **Has comments**: Fix the issues, commit, push, continue to next task
```bash
# Check for new reviews
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
# If actionable comments, read and fix them
# Then commit and push:
git add -A && git commit -m "fix: address CodeRabbit feedback
Co-Authored-By: Claude <noreply@anthropic.com>"
git push
```
### Merging PRs
```bash
# When CodeRabbit approves (status: success), merge without admin
gh pr merge {pr_number} --squash --repo host-uk/{repo}
```
---
## Step 2: Find an Issue
Search for PHP issues across the Host UK organization.
```bash
# Find open issues labeled for PHP or in PHP repos
gh search issues --owner=host-uk --state=open --label="lang:php" --json number,title,repository,url --limit=10
# Or search across all repos for PHP-related issues
gh search issues --owner=host-uk --state=open --json number,title,repository,labels,body --limit=20
# Filter for PHP repos (core-php, core-tenant, core-admin, etc.)
```
### Issue Selection Criteria
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
2. **Dependencies**: Check if issue depends on other incomplete work
3. **Scope**: Prefer issues that can be completed in one session
4. **Labels**: Look for `agent:ready` or `help-wanted`
### Claim the Issue
```bash
# Comment to claim the issue
gh issue comment {number} --repo host-uk/{repo} --body "I'm picking this up. Starting work now."
# Assign yourself (if you have permission)
gh issue edit {number} --repo host-uk/{repo} --add-assignee @me
```
---
## Step 3: Implement the Solution
### Setup Branch
```bash
# Navigate to the package
cd packages/{repo}
# Ensure you're on main/dev and up to date
git checkout dev && git pull
# Create feature branch
git checkout -b feature/issue-{number}-{short-description}
```
### Development Workflow
1. **Read the code** - Understand the codebase structure
2. **Write tests first** - TDD approach when possible
3. **Implement the solution** - Follow Laravel/PHP best practices
4. **Run tests** - Ensure all tests pass
```bash
# Run tests
composer test
# Run linting
composer lint
# Run static analysis if available
composer analyse
```
### Code Quality Checklist
- [ ] Tests written and passing
- [ ] Code follows PSR-12 style
- [ ] No debugging code left in
- [ ] Documentation updated if needed
- [ ] Types/PHPDoc added for new methods
### Creating Sub-Issues
If the issue reveals additional work needed:
```bash
# Create a follow-up issue
gh issue create --repo host-uk/{repo} \
--title "Follow-up: {description}" \
--body "Discovered while working on #{original_issue}
## Context
{explain what was found}
## Proposed Solution
{describe the approach}
## References
- Parent issue: #{original_issue}" \
--label "lang:php,follow-up"
```
---
## Step 4: Push and Create PR
```bash
# Stage and commit
git add -A
git commit -m "feat({scope}): {description}
{longer description if needed}
Closes #{issue_number}
Co-Authored-By: Claude <noreply@anthropic.com>"
# Push
git push -u origin feature/issue-{number}-{short-description}
# Create PR
gh pr create --repo host-uk/{repo} \
--title "feat({scope}): {description}" \
--body "$(cat <<'EOF'
## Summary
{Brief description of changes}
## Changes
- {Change 1}
- {Change 2}
## Test Plan
- [ ] Unit tests added/updated
- [ ] Manual testing completed
- [ ] CI passes
Closes #{issue_number}
---
Generated with Claude Code
EOF
)"
```
---
## Step 5: Handle CodeRabbit Review
After pushing, CodeRabbit will automatically review. Track PR status:
```bash
# Add PR to pending list (note the PR number)
# PENDING_PRS+=({repo}:{pr_number})
# Check CodeRabbit status
gh api repos/host-uk/{repo}/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
```
### While Waiting
Instead of blocking, **start working on the next issue** (go to Step 2).
### When Review Arrives
```bash
# Check the review
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq '.[-1]'
# If "Actionable comments posted: N", fix them:
# 1. Read each comment
# 2. Make the fix
# 3. Commit with clear message
# 4. Push
```
### Common CodeRabbit Feedback Patterns
- **Unused variables**: Remove or use them
- **Missing type hints**: Add return types, parameter types
- **Error handling**: Add try-catch or null checks
- **Test coverage**: Add missing test cases
- **Documentation**: Add PHPDoc blocks
---
## Step 6: Merge and Close
When CodeRabbit status shows "Review completed" with state "success":
```bash
# Merge the PR (squash merge)
gh pr merge {pr_number} --squash --repo host-uk/{repo}
# The issue will auto-close if "Closes #N" was in PR body
# Otherwise, close manually:
gh issue close {number} --repo host-uk/{repo}
```
---
## Step 7: Restart Loop
After merging:
1. Remove PR from `PENDING_PRS`
2. Check remaining pending PRs for reviews
3. Pick up next issue
4. **Restart this skill** to continue the loop
```
>>> LOOP COMPLETE - Restart /php-agent to continue working <<<
```
---
## PHP Packages Reference
| Package | Type | Description |
|---------|------|-------------|
| core-php | foundation | Core framework - events, modules, lifecycle |
| core-tenant | module | Multi-tenancy, workspaces, users |
| core-admin | module | Admin panel, Livewire, Flux UI |
| core-api | module | REST API, webhooks |
| core-mcp | module | MCP server framework |
| core-agentic | module | AI agent orchestration |
| core-bio | product | Link-in-bio pages |
| core-social | product | Social media scheduling |
| core-analytics | product | Privacy-first analytics |
| core-commerce | module | Billing, Stripe |
| core-content | module | CMS, pages, blog |
---
## Troubleshooting
### CodeRabbit Not Reviewing
```bash
# Check if CodeRabbit is enabled for the repo
gh api repos/host-uk/{repo} --jq '.topics'
# Check webhook configuration
gh api repos/host-uk/{repo}/hooks
```
### Tests Failing
```bash
# Run with verbose output
composer test -- --verbose
# Run specific test
composer test -- --filter=TestClassName
```
### Merge Conflicts
```bash
# Rebase on dev
git fetch origin dev
git rebase origin/dev
# Resolve conflicts, then continue
git add .
git rebase --continue
git push --force-with-lease
```
---
## Best Practices
1. **One issue per PR** - Keep changes focused
2. **Small commits** - Easier to review and revert
3. **Descriptive messages** - Help future maintainers
4. **Test coverage** - Don't decrease coverage
5. **Documentation** - Update if behavior changes
## Labels Reference
- `lang:php` - PHP code changes
- `agent:ready` - Ready for AI agent pickup
- `good-first-issue` - Simple, well-defined tasks
- `priority:high` - Should be addressed soon
- `follow-up` - Created from another issue
- `needs:review` - Awaiting human review

View file

@ -0,0 +1,33 @@
{
"name": "Core Developer",
"image": "ghcr.io/host-uk/core-images:developer",
"workspaceMount": "source=${localWorkspaceFolder}/packages,target=/workspace,type=bind",
"workspaceFolder": "/workspace",
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind,readonly",
"source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,readonly",
"source=core-dev-home,target=/root,type=volume"
],
"containerEnv": {
"TERM": "xterm-256color",
"EDITOR": "nvim"
},
"customizations": {
"vscode": {
"extensions": [
"bmewburn.vscode-intelephense-client",
"golang.go",
"ms-python.python",
"rust-lang.rust-analyzer"
]
}
},
"postCreateCommand": "echo 'Core Developer ready. Workspace: /workspace (packages/)'",
"remoteUser": "root"
}

10
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,10 @@
# Default owners for everything
* @host-uk/core-maintainers
# Scripts and CI
/scripts/ @host-uk/devops
/.github/ @host-uk/devops
# Documentation
*.md @host-uk/docs
/docs/ @host-uk/docs

51
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,51 @@
name: Bug Report
description: Report a problem with the developer workspace or scripts
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting! Please fill out the details below.
- type: dropdown
id: os
attributes:
label: Operating System
options:
- macOS
- Windows
- Linux (Ubuntu/Debian)
- Linux (Other)
validations:
required: true
- type: input
id: script
attributes:
label: Script/Command
description: Which script or command failed?
placeholder: "e.g., make setup, install-deps.ps1, core doctor"
validations:
required: true
- type: textarea
id: description
attributes:
label: What happened?
description: Describe the issue
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behaviour
description: What should have happened?
- type: textarea
id: logs
attributes:
label: Error output
description: Paste any error messages
render: shell

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Discussions
url: https://github.com/host-uk/core-devops/discussions
about: Ask questions and discuss ideas
- name: Security Issues
url: https://github.com/host-uk/core-devops/security/policy
about: Report security vulnerabilities privately

View file

@ -0,0 +1,58 @@
name: Feature Request
description: Suggest an improvement to the developer workspace
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for the suggestion! Please describe your idea below.
- type: dropdown
id: area
attributes:
label: Area
options:
- Setup scripts (install-deps, install-core)
- Core CLI commands
- Documentation
- IDE configuration
- CI/CD workflows
- Other
validations:
required: true
- type: textarea
id: problem
attributes:
label: Problem or use case
description: What problem does this solve?
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed solution
description: How would you like it to work?
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Any other approaches you've thought about?
- type: dropdown
id: complexity
attributes:
label: Estimated complexity
description: How much work do you think this requires?
options:
- "Small - Quick fix, single file, < 1 hour"
- "Medium - Multiple files, few hours to a day"
- "Large - Significant changes, multiple days"
- "Unknown - Not sure"
validations:
required: false

25
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,25 @@
## Summary
<!-- Brief description of changes -->
## Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation
- [ ] CI/CD improvement
- [ ] Other: <!-- describe -->
## Checklist
- [ ] Scripts tested on target OS (macOS/Windows/Linux)
- [ ] Documentation updated if needed
- [ ] No secrets or credentials in code
## Testing
<!-- How did you test these changes? -->
## Related issues
<!-- Link any related issues: Fixes #123, Relates to #456 -->

24
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,24 @@
version: 2
updates:
# GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "ci(deps)"
labels:
- "dependencies"
- "github-actions"
# Go modules (for core CLI when built locally)
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "chore(deps)"
labels:
- "dependencies"
- "go"
open-pull-requests-limit: 5

View file

@ -0,0 +1,23 @@
name: Dockerfile Lint
on:
push:
branches: [dev, main]
paths: ['**/Dockerfile*', '**.dockerfile']
pull_request:
branches: [dev, main]
paths: ['**/Dockerfile*', '**.dockerfile']
workflow_dispatch:
jobs:
hadolint:
name: Hadolint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
recursive: true
failure-threshold: warning

View file

@ -0,0 +1,50 @@
name: PHP Security
on:
push:
branches: [dev, main]
pull_request:
branches: [dev, main]
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
contents: read
security-events: write
jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run PHPStan
run: vendor/bin/phpstan analyse --error-format=github || true
semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
run: semgrep scan --config auto --sarif --output results.sarif || true
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
if: always()

View file

@ -0,0 +1,24 @@
name: Shell Lint
on:
push:
branches: [dev, main]
paths: ['**.sh', '**.bash', 'scripts/**']
pull_request:
branches: [dev, main]
paths: ['**.sh', '**.bash', 'scripts/**']
workflow_dispatch:
jobs:
shellcheck:
name: ShellCheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
severity: warning
scandir: '.'
format: gcc

126
.github/workflows/ai-worker.yml vendored Normal file
View file

@ -0,0 +1,126 @@
name: AI Worker (Free Tier)
# Runs on contributor's fork - uses THEIR API allowances
# Gemini 2.0 Flash: 1500 req/day free
# Jules: Available to all GitHub users
on:
pull_request:
types: [opened, synchronize]
issues:
types: [labeled]
permissions:
contents: write
pull-requests: write
issues: write
env:
# Contributors set their own GEMINI_API_KEY in fork secrets
# Free tier: 1500 requests/day, 1M tokens/min
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
jobs:
# Analyze PR with Gemini (contributor's free tier)
gemini-review:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get diff
id: diff
run: |
DIFF=$(git diff origin/${{ github.base_ref }}...HEAD | head -c 50000)
echo "diff<<EOFMARKER" >> $GITHUB_OUTPUT
echo "$DIFF" >> $GITHUB_OUTPUT
echo "EOFMARKER" >> $GITHUB_OUTPUT
- name: Gemini Analysis
if: env.GEMINI_API_KEY != ''
id: gemini
run: |
# Call Gemini 2.0 Flash (free tier)
RESPONSE=$(curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=$GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d @- << 'PAYLOAD'
{
"contents": [{
"parts": [{
"text": "Review this code diff. Be concise. List: 1) Security issues 2) Bugs 3) Improvements. If none, say 'LGTM'.\n\nDiff:\n${{ steps.diff.outputs.diff }}"
}]
}],
"generationConfig": {
"temperature": 0.2,
"maxOutputTokens": 1000
}
}
PAYLOAD
)
# Extract text from response
REVIEW=$(echo "$RESPONSE" | jq -r '.candidates[0].content.parts[0].text // "Analysis failed"')
echo "review<<EOFMARKER" >> $GITHUB_OUTPUT
echo "$REVIEW" >> $GITHUB_OUTPUT
echo "EOFMARKER" >> $GITHUB_OUTPUT
- name: Post Gemini review
if: steps.gemini.outputs.review != ''
uses: actions/github-script@v7
with:
script: |
const review = `${{ steps.gemini.outputs.review }}`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## 🤖 Gemini Analysis (Free Tier)\n\n${review}\n\n---\n_Powered by contributor's Gemini API allowance (1500 req/day free)_`
});
# Trigger Jules to fix issues (contributor's Copilot allowance)
trigger-jules:
if: github.event_name == 'issues' && github.event.label.name == 'agent:ready'
runs-on: ubuntu-latest
steps:
- name: Check Jules eligibility
id: check
uses: actions/github-script@v7
with:
script: |
// Check if this repo has Copilot coding agent enabled
const issue = context.payload.issue;
console.log(`Issue #${issue.number}: ${issue.title}`);
console.log(`Labels: ${issue.labels.map(l => l.name).join(', ')}`);
// Jules can be assigned to issues with specific labels
const hasAgentic = issue.labels.some(l => l.name === 'agentic');
return { eligible: hasAgentic, issueNumber: issue.number };
- name: Assign to Jules
if: steps.check.outputs.result != ''
uses: actions/github-script@v7
with:
script: |
// Trigger Jules by adding the copilot label
// Jules will pick up the issue and create a PR
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
labels: ['copilot'] // This triggers Jules/Copilot coding agent
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: `## 🤖 Jules Activated\n\nThis issue has been assigned to GitHub Copilot coding agent (Jules).\n\nJules will:\n1. Analyze the issue\n2. Create a solution\n3. Open a PR with the fix\n\n_Using contributor's Copilot allowance_ 🆓`
});
} catch (e) {
console.log('Could not assign to Jules:', e.message);
}

110
.github/workflows/auto-label.yml vendored Normal file
View file

@ -0,0 +1,110 @@
name: Auto Label Issues
on:
issues:
types: [opened, edited]
permissions:
issues: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- name: Auto-label based on content
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const title = issue.title.toLowerCase();
const body = (issue.body || '').toLowerCase();
const content = title + ' ' + body;
const labelsToAdd = [];
// Type labels based on title prefix
if (title.includes('[bug]')) {
labelsToAdd.push('bug');
} else if (title.includes('[feature]') || title.includes('feat(') || title.includes('feat:')) {
labelsToAdd.push('enhancement');
} else if (title.includes('[docs]') || title.includes('docs(') || title.includes('docs:')) {
labelsToAdd.push('documentation');
}
// Project labels based on content
if (content.includes('core dev') || content.includes('core work') || content.includes('core commit') || content.includes('core push')) {
labelsToAdd.push('project:core-cli');
}
if (content.includes('core php') || content.includes('composer') || content.includes('pest') || content.includes('phpstan')) {
labelsToAdd.push('project:core-php');
}
if (content.includes('setup') || content.includes('install') || content.includes('makefile')) {
labelsToAdd.push('project:workstation');
}
// Priority detection
if (content.includes('critical') || content.includes('urgent') || content.includes('breaking')) {
labelsToAdd.push('priority:high');
}
// Agent labels
if (content.includes('agent') || content.includes('ai ') || content.includes('claude') || content.includes('agentic')) {
labelsToAdd.push('agentic');
}
// Complexity - from template dropdown or heuristics
if (body.includes('small - quick fix')) {
labelsToAdd.push('complexity:small');
labelsToAdd.push('good first issue');
} else if (body.includes('medium - multiple files')) {
labelsToAdd.push('complexity:medium');
} else if (body.includes('large - significant')) {
labelsToAdd.push('complexity:large');
} else if (!body.includes('unknown - not sure')) {
// Heuristic complexity detection
const checklistCount = (body.match(/- \[ \]/g) || []).length;
const codeBlocks = (body.match(/```/g) || []).length / 2;
const sections = (body.match(/^##/gm) || []).length;
const fileRefs = (body.match(/\.(go|php|js|ts|yml|yaml|json|md)\b/g) || []).length;
const complexKeywords = ['refactor', 'rewrite', 'migration', 'breaking change', 'across repos', 'architecture'];
const simpleKeywords = ['simple', 'quick fix', 'typo', 'minor', 'trivial'];
const hasComplexKeyword = complexKeywords.some(k => content.includes(k));
const hasSimpleKeyword = simpleKeywords.some(k => content.includes(k));
let score = checklistCount * 2 + codeBlocks + sections + fileRefs;
score += hasComplexKeyword ? 5 : 0;
score -= hasSimpleKeyword ? 3 : 0;
if (hasSimpleKeyword || score <= 2) {
labelsToAdd.push('complexity:small');
labelsToAdd.push('good first issue');
} else if (score <= 6) {
labelsToAdd.push('complexity:medium');
} else {
labelsToAdd.push('complexity:large');
}
}
// Apply labels if any detected
if (labelsToAdd.length > 0) {
// Filter to only existing labels
const existingLabels = await github.rest.issues.listLabelsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
const validLabels = existingLabels.data.map(l => l.name);
const filteredLabels = labelsToAdd.filter(l => validLabels.includes(l));
if (filteredLabels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: filteredLabels
});
console.log(`Added labels: ${filteredLabels.join(', ')}`);
}
}

36
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: CodeQL
on:
push:
branches: [dev, main]
pull_request:
branches: [dev, main]
schedule:
- cron: "0 6 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:javascript"

57
.github/workflows/contributor-ci.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Contributor CI
# Runs on fork's compute allowance (Microsoft/GitHub free tier)
# Heavy analysis happens here, not on upstream
on:
push:
branches-ignore: [main, dev] # Only feature branches (forks)
pull_request:
branches: [main, dev]
jobs:
# This runs on CONTRIBUTOR'S allowance
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run analysis
run: |
echo "## 🔍 Contributor Analysis" >> $GITHUB_STEP_SUMMARY
echo "This CI runs on your fork's GitHub Actions allowance." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Add your heavy analysis here - it's FREE for contributors
# - CodeQL scanning
# - Dependency analysis
# - AI-powered code review (if using Copilot)
# - Full test suite
- name: Lint
run: |
# Linting on contributor's compute
echo "Running lint..."
- name: Security scan
run: |
# Security scanning on contributor's compute
echo "Running security scan..."
# AI-powered analysis (uses contributor's Copilot/AI allowance)
ai-review:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: AI Analysis Placeholder
run: |
echo "## 🤖 AI Analysis" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "This would run AI analysis using:" >> $GITHUB_STEP_SUMMARY
echo "- Contributor's Copilot allowance" >> $GITHUB_STEP_SUMMARY
echo "- GitHub's free AI features" >> $GITHUB_STEP_SUMMARY
echo "- Any AI APIs the contributor has configured" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Upstream repo pays nothing. 💰" >> $GITHUB_STEP_SUMMARY

58
.github/workflows/docs.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Deploy Docs
on:
push:
branches: [dev, main]
paths:
- 'doc/**'
- '.vitepress/**'
- 'package.json'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Install dependencies
run: npm install
- name: Build with VitePress
run: npm run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: .vitepress/dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

120
.github/workflows/fork-ai-triage.yml vendored Normal file
View file

@ -0,0 +1,120 @@
name: AI Triage (Fork Compute)
# Strategy: Heavy AI analysis runs on contributor's fork
# They get free GitHub Copilot / Actions minutes
# We only do lightweight verification
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
# Runs on contributor's GitHub Actions allowance
ai-triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changes
run: |
FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | head -50)
echo "files<<EOF" >> $GITHUB_OUTPUT
echo "$FILES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "count=$(echo "$FILES" | wc -l)" >> $GITHUB_OUTPUT
- name: Categorize changes
id: categorize
run: |
# Determine what type of changes (runs on fork's compute)
PHP_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -c '\.php$' || echo 0)
GO_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -c '\.go$' || echo 0)
JS_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -cE '\.(js|ts)$' || echo 0)
DOC_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -cE '\.(md|txt)$' || echo 0)
echo "php=$PHP_COUNT" >> $GITHUB_OUTPUT
echo "go=$GO_COUNT" >> $GITHUB_OUTPUT
echo "js=$JS_COUNT" >> $GITHUB_OUTPUT
echo "docs=$DOC_COUNT" >> $GITHUB_OUTPUT
# Suggest labels
LABELS=""
[ "$PHP_COUNT" -gt 0 ] && LABELS="$LABELS,lang:php"
[ "$GO_COUNT" -gt 0 ] && LABELS="$LABELS,lang:go"
[ "$JS_COUNT" -gt 0 ] && LABELS="$LABELS,lang:js"
[ "$DOC_COUNT" -gt 0 ] && LABELS="$LABELS,type:docs"
echo "labels=${LABELS#,}" >> $GITHUB_OUTPUT
- name: Security quick scan
run: |
# Quick security checks (contributor's compute)
echo "Checking for secrets..."
# Check for common secret patterns
if git diff origin/${{ github.base_ref }}...HEAD | grep -iE '(api_key|secret|password|token)\s*[:=]' | grep -v 'example\|placeholder\|xxx'; then
echo "::warning::Possible secrets detected in diff"
fi
# Check for .env files
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.env$'; then
echo "::error::Environment file changes detected - review carefully"
fi
- name: Generate triage summary
uses: actions/github-script@v7
with:
script: |
const changes = `${{ steps.changes.outputs.files }}`.split('\n').filter(f => f);
const labels = '${{ steps.categorize.outputs.labels }}'.split(',').filter(l => l);
const summary = `## 🤖 AI Triage Summary
**Files changed:** ${changes.length}
**Languages detected:** ${labels.filter(l => l.startsWith('lang:')).map(l => l.replace('lang:', '')).join(', ') || 'none'}
### Suggested labels
${labels.map(l => '`' + l + '`').join(' ') || '_No suggestions_'}
### Changed files
<details>
<summary>View ${changes.length} files</summary>
\`\`\`
${changes.join('\n')}
\`\`\`
</details>
---
_This analysis ran on the contributor's GitHub Actions allowance._ 🆓
`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: summary
});
- name: Apply suggested labels
if: steps.categorize.outputs.labels != ''
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
const labels = '${{ steps.categorize.outputs.labels }}'.split(',').filter(l => l);
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labels
});
}

37
.github/workflows/fork-pr-analysis.yml vendored Normal file
View file

@ -0,0 +1,37 @@
name: PR Analysis (Fork)
# This workflow runs on the FORK's resources, not ours
# Contributors get free GitHub Actions minutes
# Microsoft/GitHub subsidizes the compute
on:
pull_request_target:
types: [opened, synchronize]
jobs:
# Lightweight check on our side - just verify the fork did the work
verify-fork-ci:
runs-on: ubuntu-latest
steps:
- name: Check fork CI status
uses: actions/github-script@v7
with:
script: |
const { data: checks } = await github.rest.checks.listForRef({
owner: context.payload.pull_request.head.repo.owner.login,
repo: context.payload.pull_request.head.repo.name,
ref: context.payload.pull_request.head.sha
});
const passed = checks.check_runs.filter(c => c.conclusion === 'success');
const failed = checks.check_runs.filter(c => c.conclusion === 'failure');
console.log(`Fork CI: ${passed.length} passed, ${failed.length} failed`);
if (failed.length > 0) {
core.setFailed('Fork CI has failures - contributor must fix on their fork');
}
---
# This file goes in the TEMPLATE so forks inherit it
# The heavy work runs on contributor's GitHub Actions allowance

145
.github/workflows/free-tier-ai.yml vendored Normal file
View file

@ -0,0 +1,145 @@
name: Free Tier AI Analysis
on:
pull_request:
types: [opened, synchronize]
issues:
types: [opened, labeled]
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
jobs:
# Groq - 14,400 requests/day FREE (Llama 3, Mixtral)
groq-analysis:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get diff
id: diff
run: |
git diff origin/${{ github.base_ref }}...HEAD > /tmp/diff.txt
head -c 30000 /tmp/diff.txt > /tmp/diff_truncated.txt
- name: Groq Analysis
if: env.GROQ_API_KEY != ''
env:
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
run: |
# Groq is FAST and FREE (14,400 req/day)
DIFF=$(cat /tmp/diff_truncated.txt | jq -Rs .)
curl -s https://api.groq.com/openai/v1/chat/completions \
-H "Authorization: Bearer $GROQ_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"llama-3.3-70b-versatile\",
\"messages\": [{
\"role\": \"user\",
\"content\": \"Review this diff for security issues, bugs, and code smells. Be very concise. Output as: SECURITY: x issues, BUGS: x issues, SMELLS: x issues. Then list critical items only.\n\nDiff:\n${DIFF}\"
}],
\"temperature\": 0.1,
\"max_tokens\": 500
}" | jq -r '.choices[0].message.content' > /tmp/groq_review.txt
cat /tmp/groq_review.txt
# Mistral - Free tier available
mistral-analysis:
if: github.event_name == 'pull_request' && vars.MISTRAL_API_KEY != ''
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Mistral Code Review
env:
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
run: |
echo "Mistral analysis would run here"
# Similar pattern to Groq
# Cohere - 1000 req/month free (good for classification)
cohere-classify:
if: github.event_name == 'issues'
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Classify Issue
if: env.COHERE_API_KEY != ''
env:
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
run: |
# Use Cohere to classify issue type/priority
TITLE="${{ github.event.issue.title }}"
BODY="${{ github.event.issue.body }}"
curl -s https://api.cohere.ai/v1/classify \
-H "Authorization: Bearer $COHERE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"inputs\": [\"$TITLE\"],
\"examples\": [
{\"text\": \"App crashes on login\", \"label\": \"bug\"},
{\"text\": \"Add dark mode\", \"label\": \"feature\"},
{\"text\": \"SQL injection in auth\", \"label\": \"security\"},
{\"text\": \"Slow page load\", \"label\": \"performance\"}
]
}" | jq '.classifications[0].prediction'
# Cloudflare Workers AI - 10,000 neurons/day FREE
cloudflare-ai:
if: github.event_name == 'pull_request' && vars.CF_ACCOUNT_ID != ''
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Cloudflare AI Analysis
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ACCOUNT_ID: ${{ vars.CF_ACCOUNT_ID }}
run: |
# Cloudflare Workers AI - runs at the edge
echo "Cloudflare AI analysis would run here"
# @cf/meta/llama-3-8b-instruct is free
# Aggregate results and create summary
aggregate:
needs: [groq-analysis]
if: always() && github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Create Summary
uses: actions/github-script@v7
with:
script: |
const summary = `## 🤖 Free Tier AI Analysis
Multiple AI services analyzed this PR:
| Service | Status | Free Tier |
|---------|--------|-----------|
| Groq (Llama 3) | ${{ needs.groq-analysis.result }} | 14,400 req/day |
| Mistral | skipped | 1M tokens/month |
| Cohere | skipped | 1000 req/month |
| Cloudflare AI | skipped | 10K neurons/day |
---
_Add API keys to your fork secrets to enable more services._
_All analysis runs on contributor's free tier allowance._
`;
// Only comment if at least one analysis ran
if ('${{ needs.groq-analysis.result }}' !== 'skipped') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: summary
});
}

163
.github/workflows/free-tier-scanners.yml vendored Normal file
View file

@ -0,0 +1,163 @@
name: Free Tier Security Scanners
on:
push:
branches: [dev, main]
pull_request:
branches: [dev, main]
schedule:
- cron: '0 6 * * 1' # Weekly Monday 6am
permissions:
contents: read
security-events: write
pull-requests: write
jobs:
# Semgrep - FREE, powerful SAST
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- name: Semgrep Scan
run: |
semgrep scan --config auto --sarif --output semgrep.sarif || true
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif
if: always()
continue-on-error: true
# Trivy - FREE container/IaC scanner
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy Vulnerability Scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy.sarif'
severity: 'CRITICAL,HIGH'
continue-on-error: true
- name: Upload Trivy SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy.sarif
if: always()
continue-on-error: true
# Gitleaks - FREE secret scanner
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Gitleaks Scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
# OSV-Scanner - FREE vulnerability DB from Google
osv-scanner:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: OSV Scanner
uses: google/osv-scanner-action@v1
with:
scan-args: |-
--recursive
--format=sarif
--output=osv.sarif
.
continue-on-error: true
- name: Upload OSV SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: osv.sarif
if: always()
continue-on-error: true
# Checkov - FREE IaC scanner
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov Scan
uses: bridgecrewio/checkov-action@v12
with:
directory: .
framework: all
output_format: sarif
output_file_path: checkov.sarif
continue-on-error: true
- name: Upload Checkov SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: checkov.sarif
if: always()
continue-on-error: true
# Aggregate all findings for core CLI to consume
aggregate-findings:
needs: [semgrep, trivy, gitleaks, osv-scanner, checkov]
if: always()
runs-on: ubuntu-latest
steps:
- name: Summary
run: |
echo "## 🔍 Security Scan Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Scanner | Status | Free Tier |" >> $GITHUB_STEP_SUMMARY
echo "|---------|--------|-----------|" >> $GITHUB_STEP_SUMMARY
echo "| Semgrep | ${{ needs.semgrep.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
echo "| Trivy | ${{ needs.trivy.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
echo "| Gitleaks | ${{ needs.gitleaks.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
echo "| OSV-Scanner | ${{ needs.osv-scanner.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
echo "| Checkov | ${{ needs.checkov.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Results uploaded to GitHub Security tab." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "_All scanners are 100% free. No API keys needed._" >> $GITHUB_STEP_SUMMARY
- name: Create findings artifact for core CLI
run: |
# Create JSON summary for core CLI to consume
cat > findings.json << 'FINDINGS'
{
"timestamp": "${{ github.event.head_commit.timestamp }}",
"commit": "${{ github.sha }}",
"scanners": {
"semgrep": "${{ needs.semgrep.result }}",
"trivy": "${{ needs.trivy.result }}",
"gitleaks": "${{ needs.gitleaks.result }}",
"osv": "${{ needs.osv-scanner.result }}",
"checkov": "${{ needs.checkov.result }}"
},
"security_tab": "https://github.com/${{ github.repository }}/security/code-scanning"
}
FINDINGS
cat findings.json
- uses: actions/upload-artifact@v4
with:
name: security-findings
path: findings.json
retention-days: 30

64
.github/workflows/jules-dispatch.yml vendored Normal file
View file

@ -0,0 +1,64 @@
name: Jules Task Dispatch
# Dispatch tasks to Jules (Copilot coding agent)
# Jules works on the contributor's fork using their Copilot Pro allowance
on:
issue_comment:
types: [created]
jobs:
dispatch-to-jules:
# Trigger when someone comments "@jules" or "/jules"
if: contains(github.event.comment.body, '@jules') || contains(github.event.comment.body, '/jules')
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Parse Jules command
id: parse
uses: actions/github-script@v7
with:
script: |
const comment = context.payload.comment.body;
// Extract task from comment
// Format: @jules <task description>
// or: /jules fix the bug in auth.php
const match = comment.match(/(?:@jules|\/jules)\s+(.+)/i);
const task = match ? match[1].trim() : null;
return { task, commenter: context.payload.comment.user.login };
- name: Create Jules task
uses: actions/github-script@v7
with:
script: |
const result = ${{ steps.parse.outputs.result }};
if (!result.task) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `@${result.commenter} Please specify a task for Jules:\n\n\`@jules fix the authentication bug\`\n\`@jules add unit tests for User model\`\n\`@jules refactor this to use async/await\``
});
return;
}
// Add copilot label to trigger Jules
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['copilot', 'agent:wip']
});
// Create a sub-issue or task for Jules
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## 🤖 Jules Task Queued\n\n**Task:** ${result.task}\n**Requested by:** @${result.commenter}\n\nJules (Copilot coding agent) will work on this using the repository owner's Copilot allowance.\n\n---\n_Tip: Fork this repo to use your own Copilot Pro allowance for faster processing._`
});

140
.github/workflows/template-bootstrap.yml vendored Normal file
View file

@ -0,0 +1,140 @@
name: Bootstrap from Template
on:
push:
branches: [main, dev]
workflow_dispatch:
inputs:
repo_type:
description: 'Repository type'
required: true
default: 'module'
type: choice
options:
- foundation
- module
- product
- service
- infra
- template
jobs:
bootstrap:
# Only run if this looks like a fresh repo (no releases, few commits)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if bootstrap needed
id: check
run: |
COMMIT_COUNT=$(git rev-list --count HEAD)
if [ "$COMMIT_COUNT" -lt 5 ]; then
echo "needs_bootstrap=true" >> $GITHUB_OUTPUT
echo "Fresh repo detected ($COMMIT_COUNT commits)"
else
echo "needs_bootstrap=false" >> $GITHUB_OUTPUT
echo "Existing repo ($COMMIT_COUNT commits) - skipping bootstrap"
fi
- name: Create standard labels
if: steps.check.outputs.needs_bootstrap == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Agent workflow labels
gh label create "agent:ready" --description "Task ready for AI agent" --color "0E8A16" --force || true
gh label create "agent:wip" --description "Work in progress by agent" --color "F9D0C4" --force || true
gh label create "agent:review" --description "Needs verification" --color "FBCA04" --force || true
gh label create "agent:blocked" --description "Needs human input" --color "D93F0B" --force || true
gh label create "verified" --description "Work verified" --color "0E8A16" --force || true
gh label create "verify-failed" --description "Verification failed" --color "D93F0B" --force || true
gh label create "agentic" --description "AI-consumable task" --color "5319E7" --force || true
# Type labels
gh label create "type:feature" --description "New feature" --color "0052CC" --force || true
gh label create "type:bug" --description "Bug fix" --color "D93F0B" --force || true
gh label create "type:security" --description "Security issue" --color "D93F0B" --force || true
gh label create "type:docs" --description "Documentation" --color "0075CA" --force || true
# Priority labels
gh label create "priority:critical" --description "Critical priority" --color "B60205" --force || true
gh label create "priority:high" --description "High priority" --color "D93F0B" --force || true
gh label create "priority:medium" --description "Medium priority" --color "FBCA04" --force || true
gh label create "priority:low" --description "Low priority" --color "0E8A16" --force || true
echo "✅ Labels created"
- name: Set dev as default branch
if: steps.check.outputs.needs_bootstrap == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Create dev branch if it doesn't exist
git checkout -b dev 2>/dev/null || git checkout dev
git push origin dev --force-with-lease || true
# Set as default (requires admin token, may fail with GITHUB_TOKEN)
gh repo edit --default-branch dev || echo "⚠️ Could not set default branch (needs admin)"
- name: Enable security features
if: steps.check.outputs.needs_bootstrap == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Enable vulnerability alerts
gh api -X PUT repos/${{ github.repository }}/vulnerability-alerts || true
# Enable automated security fixes
gh api -X PUT repos/${{ github.repository }}/automated-security-fixes || true
echo "✅ Security features enabled"
- name: Create setup instructions issue
if: steps.check.outputs.needs_bootstrap == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh issue create \
--title "🚀 Repository Setup Checklist" \
--label "agentic,type:docs" \
--body "## Post-Template Setup
This repo was created from the [core-devops template](https://github.com/host-uk/core-devops).
### Automated ✅
- [x] Standard labels created
- [x] Security features enabled
- [x] CodeRabbit config present
### Manual Steps
- [ ] Update \`repos.yaml\` with your package details
- [ ] Update \`CLAUDE.md\` with project-specific guidance
- [ ] Update \`README.md\` with project description
- [ ] Add to org project if needed
- [ ] Set up any required secrets (\`PROJECT_TOKEN\` for auto-project)
- [ ] Remove/customize template files
### Optional
- [ ] Enable GitHub Pages for docs
- [ ] Add to CodeRabbit (if not auto-enabled)
- [ ] Configure branch protection rules
---
_This issue was auto-created by the template bootstrap workflow._"
echo "✅ Setup issue created"
- name: Summary
if: steps.check.outputs.needs_bootstrap == 'true'
run: |
echo "## 🎉 Bootstrap Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Your repo has been configured with:" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Standard labels for agent workflow" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Security features enabled" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Setup checklist issue created" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "See the created issue for remaining manual steps." >> $GITHUB_STEP_SUMMARY

153
.github/workflows/test-setup.yml vendored Normal file
View file

@ -0,0 +1,153 @@
name: Test Setup Scripts
on:
push:
branches: [dev, main]
paths:
- 'scripts/**'
- '.github/workflows/test-setup.yml'
pull_request:
branches: [dev, main]
paths:
- 'scripts/**'
- '.github/workflows/test-setup.yml'
# Weekly test to catch upstream changes (package repos, etc.)
schedule:
- cron: '0 6 * * 1' # Every Monday at 6am UTC
workflow_dispatch: # Manual trigger
jobs:
test-linux:
name: Linux (Ubuntu)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run install-deps.sh
run: |
chmod +x scripts/install-deps.sh
./scripts/install-deps.sh
- name: Verify dependencies installed
run: |
echo "=== Checking installed tools ==="
git --version
gh --version
go version
php --version
composer --version
node --version
pnpm --version
echo "=== All dependencies verified ==="
- name: Run install-core.sh
run: |
chmod +x scripts/install-core.sh
./scripts/install-core.sh
env:
INSTALL_DIR: ${{ github.workspace }}/bin
- name: Verify core CLI installed
run: |
export PATH="${{ github.workspace }}/bin:$PATH"
core --version || echo "Core CLI version check"
core doctor || echo "Core doctor completed"
test-macos:
name: macOS
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run install-deps.sh
run: |
chmod +x scripts/install-deps.sh
./scripts/install-deps.sh
- name: Verify dependencies installed
run: |
echo "=== Checking installed tools ==="
git --version
gh --version
go version
php --version
composer --version
node --version
pnpm --version
echo "=== All dependencies verified ==="
- name: Run install-core.sh
run: |
chmod +x scripts/install-core.sh
./scripts/install-core.sh
env:
INSTALL_DIR: ${{ github.workspace }}/bin
- name: Verify core CLI installed
run: |
export PATH="${{ github.workspace }}/bin:$PATH"
core --version || echo "Core CLI version check"
core doctor || echo "Core doctor completed"
test-windows:
name: Windows
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run install-deps.ps1
shell: pwsh
run: |
# Run as current user (GitHub runners have admin)
# Modify script to skip admin check for CI
$script = Get-Content scripts/install-deps.ps1 -Raw
$script = $script -replace 'Write-Err "Please run this script as Administrator"', 'Write-Warn "Skipping admin check in CI"'
$script | Set-Content scripts/install-deps-ci.ps1
.\scripts\install-deps-ci.ps1
- name: Verify dependencies installed
shell: pwsh
run: |
Write-Host "=== Checking installed tools ==="
git --version
gh --version
go version
php --version
composer --version
node --version
pnpm --version
Write-Host "=== All dependencies verified ==="
- name: Run install-core.ps1
shell: pwsh
run: |
.\scripts\install-core.ps1
env:
INSTALL_DIR: ${{ github.workspace }}\bin
- name: Verify core CLI installed
shell: pwsh
run: |
$env:PATH = "${{ github.workspace }}\bin;$env:PATH"
core --version
core doctor
# Summary job that requires all platforms to pass
setup-complete:
name: All Platforms
needs: [test-linux, test-macos, test-windows]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check results
run: |
if [ "${{ needs.test-linux.result }}" != "success" ] || \
[ "${{ needs.test-macos.result }}" != "success" ] || \
[ "${{ needs.test-windows.result }}" != "success" ]; then
echo "One or more platform tests failed"
exit 1
fi
echo "All platform tests passed!"

14
.gitignore vendored
View file

@ -5,8 +5,15 @@ packages/*
# Core CLI cache (transient data, not config)
.core/cache/
# IDE
.idea/
# IDE - share useful configs, ignore user-specific
.idea/workspace.xml
.idea/tasks.xml
.idea/shelf/
.idea/httpRequests/
.idea/dataSources/
.idea/dataSources.local.xml
.idea/copilot*.xml
.idea/material_theme*.xml
.vscode/
*.swp
*.swo
@ -21,3 +28,6 @@ Thumbs.db
# Logs
*.log
# Template - remove these lines after setup
# !TEMPLATE_SETUP.md

17
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,17 @@
# User-specific files
/workspace.xml
/tasks.xml
/shelf/
/httpRequests/
/dataSources/
/dataSources.local.xml
/copilot*.xml
# Sensitive data
/webServers.xml
/deployment.xml
/.env
# OS/editor artifacts
*.iws
.DS_Store

79
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<!-- PHP PSR-12 Style -->
<PHPCodeStyleSettings>
<option name="ALIGN_KEY_VALUE_PAIRS" value="false" />
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="false" />
<option name="ALIGN_PHPDOC_COMMENTS" value="false" />
<option name="ALIGN_ASSIGNMENTS" value="false" />
<option name="ALIGN_MATCH_ARM_ARROW" value="false" />
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="SPACE_AFTER_UNARY_NOT" value="false" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="false" />
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
<option name="MULTILINE_CHAINED_CALLS_SEMICOLON_ON_NEW_LINE" value="true" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="COMMA_AFTER_LAST_PARAMETER" value="true" />
<option name="COMMA_AFTER_LAST_MATCH_ARM" value="true" />
<option name="BLANK_LINE_BEFORE_RETURN_STATEMENT" value="true" />
<option name="NAMESPACE_BRACE_STYLE" value="1" />
</PHPCodeStyleSettings>
<codeStyleSettings language="PHP">
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="1" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="1" />
<option name="BLANK_LINES_AROUND_CLASS" value="1" />
<option name="BLANK_LINES_AROUND_METHOD" value="1" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="CLASS_BRACE_STYLE" value="1" />
<option name="METHOD_BRACE_STYLE" value="1" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="false" />
<option name="SPACE_BEFORE_IF_PARENTHESES" value="true" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="true" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="true" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="true" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
</codeStyleSettings>
<!-- JavaScript/TypeScript -->
<codeStyleSettings language="JavaScript">
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<!-- YAML -->
<codeStyleSettings language="yaml">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
</project>

8
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
</project>

29
.idea/core-devops.iml generated Normal file
View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/packages" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-php/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-tenant/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-admin/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-api/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-mcp/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-agentic/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-bio/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-social/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-analytics/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-notify/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-trust/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-support/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-commerce/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-content/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-tools/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-uptelligence/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-developer/vendor" />
<excludeFolder url="file://$MODULE_DIR$/packages/core-template/vendor" />
<excludePattern pattern="node_modules" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

33
.idea/dictionaries/hostuk.xml generated Normal file
View file

@ -0,0 +1,33 @@
<component name="ProjectDictionaryState">
<dictionary name="hostuk">
<words>
<w>agentic</w>
<w>biohost</w>
<w>devops</w>
<w>fileable</w>
<w>hostuk</w>
<w>laravel</w>
<w>livewire</w>
<w>mcp</w>
<w>middlewares</w>
<w>multitenancy</w>
<w>namespacing</w>
<w>notifyhost</w>
<w>oauth</w>
<w>phpstan</w>
<w>pint</w>
<w>sanctum</w>
<w>serializable</w>
<w>socialhost</w>
<w>tailwindcss</w>
<w>tenancy</w>
<w>trusthost</w>
<w>uptelligence</w>
<w>uuid</w>
<w>uuids</w>
<w>vite</w>
<w>webhook</w>
<w>webhooks</w>
</words>
</dictionary>
</component>

26
.idea/inspectionProfiles/Host_UK.xml generated Normal file
View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Host UK" />
<!-- PHP Inspections -->
<inspection_tool class="PhpUnused" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingReturnTypeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMissingParamTypeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedPrivateMethodInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedPrivateFieldInspection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpArrayShapeAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<!-- Laravel-specific: don't warn about facades -->
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="ERROR" enabled_by_default="true">
<scope name="Vendor" level="INFORMATION" enabled="false" />
</inspection_tool>
<!-- Ignore TODO comments in vendor -->
<inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true">
<scope name="Vendor" level="INFORMATION" enabled="false" />
</inspection_tool>
<!-- TypeScript/JavaScript -->
<inspection_tool class="TypeScriptUnresolvedReference" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="JSUnusedLocalSymbols" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="true" />
<option name="PROJECT_PROFILE" value="Host UK" />
<version value="1.0" />
</settings>
</component>

16
.idea/laravel-idea.xml generated Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="LaravelSettings">
<option name="routeNamespaceModule" value="" />
<option name="routeNamespaceWeb" value="" />
<option name="viewPath" value="" />
<option name="routeNamespaceApi" value="" />
<option name="controllerNamespace" value="" />
<option name="basePath" value="$PROJECT_DIR$/packages/core-php" />
<option name="apiResourceNamespace" value="" />
<option name="resourceNamespace" value="" />
<option name="multipleModules" value="true" />
<option name="livewireEnabled" value="true" />
<option name="bladeDirectiveIgnorePrefix" value="" />
</component>
</project>

9
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/core-devops.iml" filepath="$PROJECT_DIR$/.idea/core-devops.iml" />
</modules>
</component>
</project>

17
.idea/php.xml generated Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpProjectSharedConfiguration" php_language_level="8.4">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/packages/core-php/vendor" />
</include_path>
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Clone All Repos" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/scripts/clone-repos.ps1" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="powershell" />
<option name="INTERPRETER_OPTIONS" value="-ExecutionPolicy Bypass -File" />
<method v="2" />
</configuration>
</component>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Composer Lint (core-php)" type="ComposerRunConfigurationType">
<option name="command" value="lint" />
<option name="workingDir" value="$PROJECT_DIR$/packages/core-php" />
<method v="2" />
</configuration>
</component>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Composer Test (core-php)" type="ComposerRunConfigurationType">
<option name="command" value="test" />
<option name="workingDir" value="$PROJECT_DIR$/packages/core-php" />
<method v="2" />
</configuration>
</component>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="PHPStan (core-php)" type="PhpUnitRunConfigurationType" factoryName="PHPUnit">
<CommandLine workingDirectory="$PROJECT_DIR$/packages/core-php" />
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" />
<option name="externalSystemIdString" value="com.jetbrains.php.phpunit" />
<option name="scriptParameters" value="analyse" />
<option name="vmOptions" />
</ExternalSystemSettings>
<EXTENSION ID="PhpQualityToolRunConfigurationExtensionSettingsManager">
<QualityTool>
<option name="tool" value="PHPStan" />
</QualityTool>
</EXTENSION>
<method v="2" />
</configuration>
</component>

4
.idea/scopes/Packages.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="DependencyValidationManager">
<scope name="Packages" pattern="file[core-devops]:packages//*" />
</component>

4
.idea/scopes/Tests.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="DependencyValidationManager">
<scope name="Tests" pattern="file[core-devops]:packages//tests//*||file[core-devops]:packages//*/Tests//*" />
</component>

4
.idea/scopes/Vendor.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="DependencyValidationManager">
<scope name="Vendor" pattern="file[core-devops]:packages//vendor//*" />
</component>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

25
.idea/watcherTasks.xml generated Normal file
View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<TaskOptions isEnabled="false">
<option name="arguments" value="$FilePath$" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" value="Laravel Pint - Format on save" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="php" />
<option name="immediateSync" value="false" />
<option name="name" value="Pint" />
<option name="output" value="" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="$ProjectFileDir$/packages/core-php/vendor/bin/pint" />
<option name="runOnExternalChanges" value="false" />
<option name="scopeName" value="Packages" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="$FileDir$" />
<envs />
</TaskOptions>
</component>
</project>

78
.vitepress/config.ts Normal file
View file

@ -0,0 +1,78 @@
import { defineConfig } from 'vitepress'
const pkg = 'devops'
const canonical = `https://core.help/packages/${pkg}/`
export default defineConfig({
title: 'Host UK DevOps',
description: 'Developer workspace orchestrator for Host UK',
srcDir: 'doc',
outDir: '.vitepress/dist',
head: [
['link', { rel: 'canonical', href: canonical }],
['meta', { property: 'og:site_name', content: 'Host UK Documentation' }],
],
themeConfig: {
nav: [
{ text: 'Home', link: '/' },
{ text: 'core.help', link: 'https://core.help' },
],
sidebar: [
{
text: 'Guide',
items: [
{ text: 'Introduction', link: '/' },
{ text: 'Quick Start', link: '/quick-start' },
{ text: 'Commands', link: '/commands' },
]
},
{
text: 'Configuration',
items: [
{ text: '.core/ Folder', link: '/core-folder' },
{ text: 'repos.yaml', link: '/repos-yaml' },
]
},
{
text: 'Reference',
items: [
{ text: 'Package Types', link: '/package-types' },
{ text: 'Troubleshooting', link: '/troubleshooting' },
]
}
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/host-uk/core-devops' }
],
footer: {
message: 'Released under the EUPL-1.2 License.',
copyright: 'Copyright © Host UK'
},
search: {
provider: 'local'
},
editLink: {
pattern: 'https://github.com/host-uk/core-devops/edit/dev/doc/:path',
text: 'Edit this page on GitHub'
}
},
sitemap: {
hostname: canonical
},
transformHead({ pageData }) {
const head: any[] = []
const pagePath = pageData.relativePath.replace(/\.md$/, '.html').replace(/index\.html$/, '')
head.push(['link', { rel: 'canonical', href: `${canonical}${pagePath}` }])
return head
}
})

View file

@ -0,0 +1,33 @@
.dev-banner {
background: linear-gradient(90deg, #7c3aed 0%, #2563eb 100%);
color: white;
padding: 0.5rem 1rem;
text-align: center;
font-size: 0.875rem;
position: sticky;
top: 0;
z-index: 100;
}
.dev-banner a {
color: #fbbf24;
font-weight: 600;
text-decoration: underline;
}
.dev-banner a:hover {
color: #fcd34d;
}
.VPNav {
top: 36px !important;
}
.VPSidebar {
top: calc(var(--vp-nav-height) + 36px) !important;
height: calc(100vh - var(--vp-nav-height) - 36px) !important;
}
.VPContent {
padding-top: 36px;
}

21
.vitepress/theme/index.ts Normal file
View file

@ -0,0 +1,21 @@
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import type { Theme } from 'vitepress'
import './custom.css'
const Banner = () => {
return h('div', { class: 'dev-banner' }, [
h('span', '📚 Developer preview. '),
h('a', { href: 'https://core.help/packages/devops/', target: '_blank' }, 'Visit core.help'),
h('span', ' for the complete documentation.')
])
}
export default {
extends: DefaultTheme,
Layout() {
return h(DefaultTheme.Layout, null, {
'layout-top': () => h(Banner)
})
}
} satisfies Theme

View file

@ -53,12 +53,38 @@ See `.core/docs/core-folder-spec.md` for the full specification that each packag
```bash
# macOS/Linux
git clone git@github.com:host-uk/core-devops.git && cd core-devops && make setup
# Windows (PowerShell as Admin)
.\scripts\install-deps.ps1 && .\scripts\install-core.ps1 && core setup
```
Environment variables for `install-core.sh`:
### Windows Setup
The `core` CLI is not yet available on Windows. Use these steps instead:
```powershell
# 1. Install dependencies (PowerShell as Admin)
.\scripts\install-deps.ps1
# 2. Authenticate GitHub CLI
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
# 3. Clone all repos
.\scripts\clone-repos.ps1
# 4. Enable PHP extensions (edit C:\tools\php84\php.ini, uncomment these):
# extension=curl
# extension=fileinfo
# extension=mbstring
# extension=openssl
# extension=pdo_sqlite
# 5. Install and test a package
cd packages/core-php
composer install
composer test
```
### Environment Variables (macOS/Linux)
For `install-core.sh`:
- `INSTALL_DIR` - Binary location (default: `~/.local/bin`)
- `BUILD_FROM_SOURCE` - `true`, `false`, or `auto` (default: `auto`, tries binary then builds)
@ -136,9 +162,16 @@ Defined in `repos.yaml`:
## Troubleshooting
- **"core: command not found"** → `make install-core` (builds from https://github.com/host-uk/core)
- **"gh: command not found"** → `brew install gh && gh auth login`
- **"gh: command not found"** → `brew install gh && gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project`
- **"refusing to allow..." or "missing required scopes"** → `gh auth refresh -h github.com -s workflow,read:project,project`
- **Clone failures**`ssh -T git@github.com` to verify SSH keys
### Windows-Specific
- **"openssl extension is required"** → Enable extensions in `C:\tools\php84\php.ini` (see setup above)
- **"composer: command not found"** → Use PowerShell, not Git Bash: `powershell -Command "composer install"`
- **core CLI not available** → Use `.\scripts\clone-repos.ps1` and work directly with composer
## This Repo's Scope
Don't add application code here. This repo only contains:

139
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,139 @@
# Contributing Compute to Host UK
**Host UK is a UK Community Interest Company (CIC)** - a social enterprise legally required to use our work for community benefit. Our assets are locked for public good, not shareholders.
## The Mission
1. **Build tools** that make development easier (core CLI, modules)
2. **Aggregate free compute** from community members' unused allowances
3. **Give back** by fixing security issues in unfunded OSS projects
The LLMs learned to code from open source. We're directing resources back to those projects.
---
## Contribute Compute (5 minutes)
You don't need to write code. Your unused free tier allowances become part of a distributed network that fixes OSS.
### Step 1: Fork this repo
```bash
gh repo fork host-uk/core-devops --clone
cd core-devops
```
### Step 2: Add your free API keys
```bash
# Gemini (1500 req/day free)
# Get key: https://aistudio.google.com/apikey
gh secret set GEMINI_API_KEY
# Groq (14,400 req/day free)
# Get key: https://console.groq.com/keys
gh secret set GROQ_API_KEY
# Optional: More services
gh secret set MISTRAL_API_KEY # https://console.mistral.ai/
gh secret set COHERE_API_KEY # https://dashboard.cohere.com/
```
### Step 3: Enable GitHub Actions
Go to your fork → Actions tab → Enable workflows
### Step 4: Done!
Your fork now:
- Runs security scans (Semgrep, Trivy, Gitleaks) - **free, no keys needed**
- Runs AI analysis when you work on PRs - **uses your free tier**
- Contributes to the distributed verification network
---
## Contribute Verification (10 min/week)
Help verify other agents' work (human or AI). No agent can verify their own work.
### Find tasks:
```bash
# Install core CLI
make install-core
# Find tasks needing verification
core issues --label agent:review
# Or browse: https://github.com/orgs/host-uk/projects/2
```
### Verify:
1. Review the implementation
2. Check tests pass
3. Add `verified` or `verify-failed` label
---
## Contribute Code
Standard PR workflow:
```bash
# Create branch
git checkout -b fix/issue-42
# Make changes, commit
git add . && git commit -m "fix: description"
# Push (CI runs on YOUR allowance, not ours)
git push origin fix/issue-42
# Create PR
gh pr create
```
Your PR will be:
- Analyzed by AI (Gemini, Groq) - your free tier
- Scanned for security issues - free
- Reviewed by CodeRabbit - free
- Verified by a different contributor
---
## The Economics
| Who | Pays For |
|-----|----------|
| Microsoft | GitHub Actions (2000 min/month per user) |
| Google | Gemini API (1500 req/day per user) |
| Groq | Llama 3 inference (14,400 req/day per user) |
| Contributors | Nothing ($0) |
| Host UK | Nothing ($0) |
| OSS Projects | Get free security fixes |
**100 contributors × free tiers = enterprise-scale compute for public good**
---
## Where the Work Goes
1. **Host UK packages** - Our tools and modules
2. **Unfunded OSS** - Popular packages with no security budget
3. **Community requests** - Projects our members depend on
We're not hoarding. We're redistributing tech resources to the commons.
---
## Questions?
- Discord: https://discord.gg/host-uk
- Issues: https://github.com/host-uk/core-devops/issues
**License:** EUPL-1.2 (copyleft, EU-recognized, compatible with GPL)
---
*Host UK CIC - Building ethical infrastructure for the open source community*

View file

@ -32,7 +32,7 @@ You're now ready to develop. The workspace starts with `core-php` as the active
core doctor
# See workspace status
core health
core dev health
# Run tests in the active package (core-php)
core php test
@ -136,7 +136,12 @@ make install-core
**"gh: command not found"**
```bash
brew install gh && gh auth login
brew install gh && gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
```
**"refusing to allow an OAuth App to create or update workflow"** or **"missing required scopes"**
```bash
gh auth refresh -h github.com -s workflow,read:project,project
```
**Clone failures**

32
SECURITY.md Normal file
View file

@ -0,0 +1,32 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| dev | :white_check_mark: |
## Reporting a Vulnerability
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them via email to: **security@host.uk.com**
Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggested fixes (optional)
You should receive a response within 48 hours. If the issue is confirmed, we will:
1. Work on a fix privately
2. Release a patch
3. Credit you in the release notes (unless you prefer anonymity)
## Security Best Practices
When contributing to this repository:
- Never commit secrets, API keys, or credentials
- Use environment variables for sensitive configuration
- Review dependencies for known vulnerabilities
- Follow the principle of least privilege in scripts

86
TEMPLATE_SETUP.md Normal file
View file

@ -0,0 +1,86 @@
# Template Setup Guide
You've created a new repo from the **core-devops** template. Follow these steps to customize it.
## Automated Setup
When you first push, the `template-bootstrap.yml` workflow will:
- ✅ Create standard labels (agent workflow, priorities, types)
- ✅ Enable security features (Dependabot, vulnerability alerts)
- ✅ Create a setup checklist issue
## Files to Customize
### Required Changes
| File | Action |
|------|--------|
| `repos.yaml` | Replace with your package registry or delete if single-repo |
| `CLAUDE.md` | Update with your project's architecture and commands |
| `README.md` | Replace with your project description |
| `package.json` | Update name, or delete if not using VitePress |
### Optional Changes
| File | Action |
|------|--------|
| `.coderabbit.yaml` | Customize review instructions for your codebase |
| `.core/workspace.yaml` | Update active package and settings |
| `doc/` | Replace with your documentation |
| `scripts/` | Keep if useful, or replace with your setup scripts |
| `Makefile` | Update targets for your workflow |
### Files to Delete (if not needed)
```bash
# If not using VitePress docs
rm -rf .vitepress doc package.json
# If not a multi-repo workspace
rm -rf packages repos.yaml .core/workspace.yaml
# This file (after reading!)
rm TEMPLATE_SETUP.md
```
## Secrets to Configure
If using the auto-project workflow:
```bash
# Org-level secret (already set if in host-uk org)
gh secret set PROJECT_TOKEN --org YOUR_ORG --visibility all
```
## Branch Strategy
The template uses `dev` as the default branch:
- `dev` - Development (default, PRs merge here)
- `main` - Production releases
To switch to `main`-only:
```bash
gh repo edit --default-branch main
```
## Adding to Org Projects
```bash
# Add repo's issues to a project when labeled
gh workflow run auto-project.yml
```
## Verification Workflow
The template includes the agent verification workflow:
```
agent:ready → agent:wip → agent:review → verified/verify-failed
```
This enforces the rule: **no agent can verify their own work**.
---
Delete this file once setup is complete:
```bash
rm TEMPLATE_SETUP.md && git add -A && git commit -m "chore: complete template setup"
```

77
TODO.md Normal file
View file

@ -0,0 +1,77 @@
# TODO - Session Summary 2026-02-01
## ✅ Completed Today
### Issue Auto-Labeling
- [x] Issue templates (bug_report.yml, feature_request.yml) for core + core-devops
- [x] Auto-label workflow detects: type, project, priority, agentic keywords
- [x] Complexity dropdown in feature request template
- [x] Heuristic complexity detection (checklist count, code blocks, sections, file refs, keywords)
- [x] Retroactively labeled unlabeled issues in core repo
- [x] Test issue #70 created and auto-labeled correctly
### GitHub Org Setup
- [x] Dev branches as default (all repos)
- [x] Labels taxonomy (agent:*, priority:*, type:*, lang:*)
- [x] Discord webhooks (7 channels × 20 repos)
- [x] Branch protection rules
- [x] Org security defaults enabled
### CodeRabbit
- [x] Central config: host-uk/coderabbit
- [x] Per-repo .coderabbit.yaml (21 repos)
- [x] review_status: false
### CodeQL/Security
- [x] Enabled on all public repos
- [x] Language-appropriate scanning
### GitHub Projects
- [x] Auto-add workflow (label → project)
- [x] PROJECT_TOKEN secret set
### Agent Verification Workflow
- [x] Labels: agent:ready → agent:wip → agent:review → verified
- [x] Self-verification blocked
- [x] core/.github/workflows/agent-verify.yml
### Template Repo (core-devops)
- [x] Bootstrap workflow for new repos
- [x] TEMPLATE_SETUP.md guide
### Free Tier Integration
- [x] Gemini, Groq, Mistral, Cohere, Cloudflare workflows
- [x] Semgrep, Trivy, Gitleaks, OSV, Checkov
- [x] Jules dispatch workflow
- [x] CONTRIBUTING.md + scripts/contribute.sh
### Docs
- [x] VitePress setup
- [x] core docs sync tested
- [x] free-tier-services.md
### Container Images (core-images)
- [x] docker-compose.yml + devcontainer.json (packages/ mount)
- [x] Dual-registry workflow: GHCR + Docker Hub (lthn/*)
- [x] DOCKERHUB_USERNAME/TOKEN secrets (org-wide)
- [ ] Fix Dockerfile Python build (#2 - tiktoken, tree-sitter)
- [ ] Merge dev → main to publish images
### Core CLI Issues
- [x] #50 - linuxkit double-dash flags fix
## 🔲 Pending (Core CLI Issues Created)
- [ ] #46 - docs sync ignores packages_dir
- [ ] #47 - core qa command area
- [ ] #48 - core security command
- [ ] #49 - core monitor (aggregate free tier findings)
## 🔲 Next Steps
- [ ] Merge dev → main on repos to deploy docs
- [ ] Recruit first 10 contributors
- [ ] Rotate PROJECT_TOKEN (was shared in chat)
- [ ] Rotate DOCKERHUB_TOKEN (was shared in chat)
- [x] Add workflow to remaining PHP repos (8 repos)
- [ ] Set up external OSS project scanning

134
doc/commands.md Normal file
View file

@ -0,0 +1,134 @@
# Commands Reference
All `core` CLI commands available in the workspace.
## Workspace Commands
### `core health`
Quick status summary of all repos.
```bash
core health
# Output: 18 repos │ 2 dirty │ synced
```
### `core work`
Full workflow: status → commit → push.
```bash
core work # Interactive
core work --status # Status table only
```
### `core commit`
Claude-assisted commits for dirty repos.
```bash
core commit # Interactive
core commit --all # Commit all without prompting
```
### `core push`
Push repos with unpushed commits.
```bash
core push # Interactive
core push --force # Push without confirmation
```
### `core pull`
Pull repos that are behind.
```bash
core pull # Interactive
core pull --all # Pull all repos
```
## GitHub Integration
### `core issues`
List open issues across repos.
```bash
core issues # All open issues
core issues --assignee @me # Assigned to you
```
### `core reviews`
List PRs needing review.
```bash
core reviews
```
### `core ci`
GitHub Actions workflow status.
```bash
core ci
```
## Analysis
### `core impact`
Show what depends on a package.
```bash
core impact core-php
```
## Package Commands
### `core php test`
Run Pest tests in the active package.
```bash
core php test
core php test --filter=ClassName
```
### `core php lint`
Run Pint linter in the active package.
```bash
core php lint
```
### `core php dev`
Start Vite dev server in the active package.
```bash
core php dev
```
## Setup Commands
### `core setup`
Clone repos into the workspace.
```bash
core setup # Default (foundation + module)
core setup --only foundation,module # Specific types
```
### `core doctor`
Check environment health.
```bash
core doctor # Check only
core doctor --fix # Attempt to fix issues
```

80
doc/core-folder.md Normal file
View file

@ -0,0 +1,80 @@
# .core/ Folder
The `.core/` folder provides workspace configuration and Claude Code integration.
## Structure
```
.core/
├── workspace.yaml # Workspace configuration
├── plugin/
│ ├── plugin.json # Claude Code manifest
│ ├── skills/ # Context-aware skills
│ └── hooks/ # Command hooks
└── docs/
└── core-folder-spec.md # Full specification
```
## workspace.yaml
Defines the active package and workspace settings.
```yaml
version: 1
# Active package for `core php test`, etc.
active: core-php
# Default package types for `core setup`
default_only:
- foundation
- module
# Paths
packages_dir: ./packages
# Settings
settings:
suggest_core_commands: true
show_active_in_prompt: true
```
## Changing Active Package
Edit `.core/workspace.yaml`:
```yaml
active: core-tenant
```
Then commands run from workspace root target that package:
```bash
core php test # Now runs in core-tenant
```
## Claude Code Plugin
The `plugin/` folder integrates with Claude Code:
### plugin.json
Manifest defining skills and commands.
### skills/
Markdown files providing context-aware guidance:
- `workspace.md` - Multi-repo navigation
- `switch-package.md` - Package switching
- `package-status.md` - Status checking
### hooks/
Shell scripts that run before/after commands:
- `prefer-core.sh` - Suggests `core` commands
## Full Specification
See `.core/docs/core-folder-spec.md` for the complete specification that packages should follow.

103
doc/free-tier-compute.md Normal file
View file

@ -0,0 +1,103 @@
# Free Tier Compute Guide
This project uses distributed compute from contributors' free tier allowances. Here's how to maximize it.
## GitHub Actions (Microsoft)
**Free tier:** 2,000 minutes/month for public repos
When you fork this repo, CI runs on YOUR allowance, not upstream's. This includes:
- Full test suite
- Linting and formatting
- Security scanning
- AI-powered triage
## Gemini API (Google)
**Free tier:** 1,500 requests/day, 1M tokens/minute
### Setup
1. Get API key: https://aistudio.google.com/apikey
2. Add to your fork's secrets:
```bash
gh secret set GEMINI_API_KEY --repo YOUR_USER/YOUR_FORK
```
The `ai-worker.yml` workflow will use your Gemini allowance for:
- Code review
- Bug detection
- Security analysis
## Jules / Copilot (GitHub)
**Free tier:** Available with GitHub Copilot (free for OSS contributors)
### Trigger Jules
Comment on any issue:
```
@jules fix the authentication bug in login.php
@jules add unit tests for the User model
@jules refactor to use async/await
```
Jules will:
1. Analyze the issue
2. Write code to fix it
3. Create a PR on your fork
4. Uses YOUR Copilot allowance
### Get Copilot Free
- Open source contributors: https://github.com/settings/copilot
- Students: GitHub Education pack
- Verified OSS maintainers: Free Copilot Pro
## CodeRabbit
**Free tier:** Unlimited for public repos
Already configured via `.coderabbit.yaml`. Reviews run automatically on PRs.
## Compute Distribution Model
```
┌────────────────────────────────────────────┐
│ CONTRIBUTOR FORK │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ GitHub │ │ Gemini │ │
│ │ Actions │ │ 2.0 Flash │ │
│ │ FREE │ │ FREE │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Jules/ │ │ CodeRabbit │ │
│ │ Copilot │ │ FREE │ │
│ │ FREE* │ │ │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ * With Copilot Pro (free for OSS) │
└────────────────────────────────────────────┘
│ PR (already analyzed)
┌────────────────────────────────────────────┐
│ UPSTREAM REPO │
│ │
│ Just verify fork CI passed ✓ │
│ Cost: ~$0.001 per PR │
└────────────────────────────────────────────┘
```
## For Donor Fleet Members
If you want to contribute compute without coding:
1. Fork the repo
2. Set up your API keys (Gemini, etc.)
3. Keep Actions enabled
4. Pick up `agent:review` tasks to verify others' work
Your free tier becomes part of the distributed compute network!

159
doc/free-tier-services.md Normal file
View file

@ -0,0 +1,159 @@
# Free Tier Services Integration
> **Host UK CIC** is a UK Community Interest Company. Our assets are legally locked for community benefit - we can't extract value for shareholders. This page documents how we aggregate free compute to benefit the open source commons.
## The Model
```
┌─────────────────────────────────────────────────────────────────┐
│ 100 CONTRIBUTORS │
│ │
│ Each contributes their FREE tier allowances: │
│ • GitHub Actions: 2000 min/month │
│ • Gemini: 1500 req/day │
│ • Groq: 14,400 req/day │
│ • Copilot: Free for OSS │
│ │
│ Total daily capacity: │
│ • 150,000 Gemini requests │
│ • 1,440,000 Groq requests │
│ • 6,666 GitHub Actions hours │
│ • Unlimited security scans │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ core monitor │
│ │
│ Aggregates findings → Creates tasks → Routes to agents │
└─────────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────────────┐
│ HOST UK PACKAGES │ │ UNFUNDED OSS PROJECTS │
│ │ │ │
│ Our tools, modules │ │ Popular packages with no │
│ │ │ security budget - we find │
│ │ │ and fix vulns, submit PRs │
└─────────────────────────┘ └─────────────────────────────────┘
```
**The LLMs learned from open source. We're giving back.**
---
## AI/LLM APIs (Contributor Keys)
| Service | Free Tier | Speed | Best For |
|---------|-----------|-------|----------|
| **Groq** | 14,400 req/day | ⚡ Fastest | Quick triage, bulk analysis |
| **Gemini 2.0** | 1500 req/day | Fast | Code review, deep analysis |
| **Mistral** | 1M tokens/month | Fast | Code generation |
| **Cohere** | 1000 req/month | Medium | Classification, embeddings |
| **Cloudflare AI** | 10K neurons/day | Edge | Low latency |
| **Together.ai** | $5 credit | Fast | Multi-model |
| **Fireworks.ai** | 600 req/min | ⚡ Fast | High throughput |
| **Cerebras** | Free tier | ⚡⚡ Fastest | Bulk inference |
### Setup (2 minutes)
```bash
# In your fork
gh secret set GEMINI_API_KEY # https://aistudio.google.com/apikey
gh secret set GROQ_API_KEY # https://console.groq.com/keys
gh secret set MISTRAL_API_KEY # https://console.mistral.ai/
```
---
## Security Scanners (No Keys Needed)
All free, unlimited, run automatically:
| Scanner | Finds | Output |
|---------|-------|--------|
| **Semgrep** | SAST vulns, code patterns | SARIF → GitHub Security |
| **Trivy** | Container vulns, IaC issues | SARIF → GitHub Security |
| **Gitleaks** | Leaked secrets, API keys | SARIF → GitHub Security |
| **OSV-Scanner** | Known CVEs (Google DB) | SARIF → GitHub Security |
| **Checkov** | IaC misconfigs | SARIF → GitHub Security |
| **CodeQL** | Deep semantic analysis | Native GitHub |
| **Dependabot** | Outdated deps | Native GitHub |
---
## Code Analysis Apps (Free for Public Repos)
Install these on your fork for extra coverage:
| App | Install | Provides |
|-----|---------|----------|
| **Snyk** | [Install](https://github.com/apps/snyk-io) | Deps + code vulns |
| **SonarCloud** | [Install](https://github.com/apps/sonarcloud) | Code quality |
| **CodeClimate** | [Install](https://github.com/apps/codeclimate) | Maintainability |
| **DeepSource** | [Install](https://github.com/apps/deepsource-io) | Autofix suggestions |
| **Codacy** | [Install](https://github.com/apps/codacy-production) | Multi-language |
| **Socket.dev** | [Install](https://github.com/apps/socket-security) | Supply chain |
| **GitGuardian** | [Install](https://github.com/apps/gitguardian) | Secret detection |
| **Aikido** | [Install](https://github.com/apps/aikido-security) | Full security suite |
| **Trunk.io** | [Install](https://github.com/apps/trunk-io) | Meta-linter (50+ tools) |
---
## AI Code Assistants (Free Tiers)
| Service | Free Access | Trigger |
|---------|-------------|---------|
| **Jules/Copilot** | OSS maintainers, students | `@jules fix this bug` |
| **Codeium** | Free forever | IDE extension |
| **Cody** | Free tier | IDE extension |
| **Amazon Q** | Free tier | IDE/CLI |
| **Continue.dev** | Free, open source | IDE extension |
---
## CI/CD Free Tiers
| Service | Free Allowance | Notes |
|---------|----------------|-------|
| **GitHub Actions** | 2000 min/month | Per user, public repos |
| **CircleCI** | 6000 min/month | Good for heavy builds |
| **GitLab CI** | 400 min/month | Alternative to GH |
| **Semaphore** | 1300 min/month | Fast builds |
| **Buildkite** | Free for OSS | Self-hosted option |
---
## Who Pays For All This?
| Provider | Why Free? |
|----------|-----------|
| **Microsoft** | GitHub market dominance, AI training data |
| **Google** | Gemini adoption, developer mindshare |
| **Groq** | Hardware showcase, market entry |
| **Others** | Developer ecosystem, future enterprise sales |
**They need OSS developers. We need compute. Fair trade.**
---
## Joining the Network
```bash
# Fork and setup (5 minutes)
gh repo fork host-uk/core-devops --clone
cd core-devops
./scripts/contribute.sh
```
Your unused free tier becomes part of a collective resource that:
1. Secures Host UK packages
2. Fixes vulnerabilities in unfunded OSS
3. Gives back to the projects that trained the AIs
**Cost: $0. Impact: Massive.**
---
*Host UK CIC - Ethical infrastructure for the open source commons*

56
doc/index.md Normal file
View file

@ -0,0 +1,56 @@
---
layout: home
hero:
name: "core-devops"
text: "Developer Workspace"
tagline: Unified entry point for Host UK development
actions:
- theme: brand
text: Quick Start
link: /quick-start
- theme: alt
text: View on GitHub
link: https://github.com/host-uk/core-devops
features:
- title: One Command Setup
details: Clone and run `make setup` to get a complete development environment with all dependencies.
- title: Multi-Repo Management
details: Manage 18+ Laravel packages from a single workspace using the `core` CLI.
- title: Agentic-First
details: Designed for AI-assisted development with structured issues and Claude Code integration.
---
# Host UK DevOps
The developer workspace orchestrator for Host UK - a federated monorepo containing 18 Laravel packages.
## What's Included
| Component | Purpose |
|-----------|---------|
| `repos.yaml` | Package registry with dependencies |
| `.core/` | Workspace configuration and Claude Code plugin |
| `scripts/` | Cross-platform setup scripts |
| `Makefile` | Setup orchestration |
## Quick Start
```bash
git clone git@github.com:host-uk/core-devops.git && cd core-devops && make setup
```
## Core CLI
The workspace is managed by the `core` CLI:
```bash
core health # Status summary
core work # Commit and push workflow
core issues # GitHub issues across repos
```
## Next Steps
- [Quick Start Guide](/quick-start) - Get up and running
- [Commands Reference](/commands) - All available commands
- [.core/ Configuration](/core-folder) - Workspace configuration

58
doc/package-types.md Normal file
View file

@ -0,0 +1,58 @@
# Package Types
Host UK packages are organised into types based on their purpose.
## Foundation
Base framework with no dependencies.
| Package | Description |
|---------|-------------|
| `core-php` | Event-driven modules, lifecycle management |
## Modules
Infrastructure services that extend the foundation.
| Package | Description | Dependencies |
|---------|-------------|--------------|
| `core-tenant` | Multi-tenancy, workspaces, users | core-php |
| `core-admin` | Admin panel, Livewire, Flux UI | core-php |
| `core-api` | REST API, rate limiting, webhooks | core-php, core-tenant |
| `core-mcp` | Model Context Protocol server | core-php |
| `core-agentic` | AI agent orchestration | core-php, core-tenant, core-mcp |
| `core-commerce` | Billing, subscriptions, Stripe | core-php, core-tenant |
| `core-content` | CMS, pages, blog posts | core-php, core-tenant |
| `core-tools` | Developer utilities | core-php |
| `core-uptelligence` | Server monitoring | core-php, core-tenant |
| `core-developer` | Developer portal, OAuth | core-php, core-tenant, core-api |
## Products
User-facing applications.
| Package | Description | Domain |
|---------|-------------|--------|
| `core-bio` | Link-in-bio pages | bio.host.uk.com |
| `core-social` | Social media scheduling | social.host.uk.com |
| `core-analytics` | Privacy-first analytics | analytics.host.uk.com |
| `core-notify` | Push notifications | notify.host.uk.com |
| `core-trust` | Social proof widgets | trust.host.uk.com |
| `core-support` | Helpdesk, ticketing | - |
## Templates
Starter templates for new projects.
| Package | Description |
|---------|-------------|
| `core-template` | Starter template |
## Meta
Workspace and tooling repos.
| Package | Description |
|---------|-------------|
| `core-devops` | This workspace |
| `core` | Go CLI and framework |

63
doc/quick-start.md Normal file
View file

@ -0,0 +1,63 @@
# Quick Start
Get a complete Host UK development environment in under 5 minutes.
## Prerequisites
- Git
- GitHub CLI (`gh`)
- SSH key configured with GitHub
## Installation
### macOS / Linux
```bash
git clone git@github.com:host-uk/core-devops.git
cd core-devops
make setup
```
### Windows (PowerShell as Admin)
```powershell
git clone git@github.com:host-uk/core-devops.git
cd core-devops
.\scripts\install-deps.ps1
.\scripts\install-core.ps1
core setup
```
## What Happens
`make setup` does three things:
1. **Installs dependencies** - PHP 8.3+, Composer, Node 20+, pnpm, GitHub CLI
2. **Installs the `core` CLI** - Multi-repo management tool
3. **Clones all packages** - Into `packages/` (foundation and modules by default)
## Verify Installation
```bash
core doctor
```
This checks that all required tools are installed and configured.
## Next Steps
```bash
# See workspace status
core health
# Run tests in the active package
core php test
# Work on a specific package
cd packages/core-php
composer test
```
## Troubleshooting
See the [Troubleshooting Guide](/troubleshooting) for common issues.

78
doc/repos-yaml.md Normal file
View file

@ -0,0 +1,78 @@
# repos.yaml
The package registry defining all repositories in the workspace.
## Format
```yaml
version: 1
org: host-uk
base_path: ./packages
repos:
core-php:
type: foundation
description: Core PHP framework
docs: true
ci: github-actions
core-tenant:
type: module
depends_on: [core-php]
description: Multi-tenancy, workspaces
defaults:
ci: github-actions
license: EUPL-1.2
branch: main
```
## Fields
### Repository Fields
| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Package type (see below) |
| `depends_on` | array | Dependencies on other packages |
| `description` | string | Short description |
| `docs` | boolean | Has documentation |
| `ci` | string | CI system (github-actions) |
| `domain` | string | Production domain (products only) |
| `clone` | boolean | Whether to clone (default: true) |
### Package Types
| Type | Purpose | Examples |
|------|---------|----------|
| `foundation` | Base framework, no dependencies | core-php |
| `module` | Infrastructure services | core-tenant, core-admin |
| `product` | User-facing applications | core-bio, core-social |
| `template` | Starter templates | core-template |
| `meta` | Workspace repos | core-devops |
## Using with CLI
```bash
# Clone specific types
core setup --only foundation,module
# Show what depends on a package
core impact core-php
```
## Dependency Graph
The `depends_on` field creates a dependency graph:
```
core-php (foundation)
├── core-tenant
├── core-admin
├── core-api
│ └── core-developer
└── core-mcp
└── core-agentic
```
Products depend on both `core-php` and `core-tenant`.

93
doc/troubleshooting.md Normal file
View file

@ -0,0 +1,93 @@
# Troubleshooting
Common issues and solutions.
## Installation Issues
### "core: command not found"
The Core CLI isn't installed or not in PATH.
```bash
make install-core
```
Or manually:
```bash
./scripts/install-core.sh
```
### "gh: command not found"
Install GitHub CLI:
```bash
# macOS
brew install gh
# Then authenticate
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
```
### Clone failures
Check your SSH keys:
```bash
ssh -T git@github.com
```
If using HTTPS:
```bash
gh auth setup-git
```
## GitHub Issues
### "refusing to allow an OAuth App to create or update workflow"
Missing `workflow` scope:
```bash
gh auth refresh -h github.com -s workflow
```
### "missing required scopes [read:project]"
Missing project scope:
```bash
gh auth refresh -h github.com -s read:project,project
```
## Workspace Issues
### Tests failing in wrong package
Check the active package in `.core/workspace.yaml`:
```yaml
active: core-php # Should match the package you're testing
```
### Packages not found
Run setup to clone packages:
```bash
core setup
```
Or clone specific types:
```bash
core setup --only foundation,module
```
## Getting Help
1. Run `core doctor` to check environment
2. Check GitHub issues: https://github.com/host-uk/core-devops/issues
3. Ask in Discord: https://discord.gg/host-uk

29
docker-compose.yml Normal file
View file

@ -0,0 +1,29 @@
# Core Developer Environment
# Mounts packages/ as /workspace in the container
services:
dev:
image: ghcr.io/host-uk/core-images:developer
container_name: core-dev
hostname: core-dev
stdin_open: true
tty: true
volumes:
# Mount packages directory as workspace
- ./packages:/workspace
# Persist home directory configs
- dev-home:/root
# SSH keys for git operations
- ~/.ssh:/root/.ssh:ro
# Git config
- ~/.gitconfig:/root/.gitconfig:ro
environment:
- TERM=xterm-256color
- EDITOR=nvim
working_dir: /workspace
# Keep container running
command: ["/bin/zsh"]
volumes:
dev-home:
name: core-dev-home

15
package.json Normal file
View file

@ -0,0 +1,15 @@
{
"name": "@host-uk/devops-docs",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
"devDependencies": {
"vitepress": "^1.5.0",
"vue": "^3.5.0"
}
}

View file

@ -123,6 +123,13 @@ repos:
description: Starter template for new projects
docs: false
# Claude Code plugin
core-claude:
type: meta
depends_on: []
description: Claude Code plugin for Host UK monorepo
docs: false
# This repo (meta)
core-devops:
type: meta

48
scripts/clone-repos.ps1 Normal file
View file

@ -0,0 +1,48 @@
# Clone all Host UK repos (Windows alternative to `core setup`)
# Run: .\scripts\clone-repos.ps1
$ErrorActionPreference = "Stop"
$repos = @(
"core-php",
"core-tenant",
"core-admin",
"core-api",
"core-mcp",
"core-agentic",
"core-bio",
"core-social",
"core-analytics",
"core-notify",
"core-trust",
"core-support",
"core-commerce",
"core-content",
"core-tools",
"core-uptelligence",
"core-developer",
"core-template"
)
$packagesDir = Join-Path $PSScriptRoot "..\packages"
Write-Host "[INFO] Cloning repos to $packagesDir" -ForegroundColor Green
foreach ($repo in $repos) {
$repoPath = Join-Path $packagesDir $repo
if (Test-Path $repoPath) {
Write-Host "[SKIP] $repo already exists" -ForegroundColor Yellow
continue
}
Write-Host "[CLONE] $repo..." -ForegroundColor Cyan
gh repo clone "host-uk/$repo" $repoPath
if ($LASTEXITCODE -ne 0) {
Write-Host "[WARN] Failed to clone $repo" -ForegroundColor Yellow
}
}
Write-Host ""
Write-Host "[DONE] Repos cloned. Run 'composer install' in each package." -ForegroundColor Green

83
scripts/contribute.sh Executable file
View file

@ -0,0 +1,83 @@
#!/bin/bash
# Host UK CIC - Contributor Setup
# One command to join the distributed compute network
set -e
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ Host UK CIC - Contributor Setup ║"
echo "║ ║"
echo "║ Your free tier allowances will help fix unfunded OSS ║"
echo "║ projects. Cost to you: \$0. Impact: Massive. ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
# Check if this is a fork
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
if [[ "$REMOTE_URL" == *"host-uk/core-devops"* ]]; then
echo "⚠️ This is the upstream repo, not your fork."
echo ""
echo "Run this instead:"
echo " gh repo fork host-uk/core-devops --clone"
echo " cd core-devops"
echo " ./scripts/contribute.sh"
exit 1
fi
echo "✓ Fork detected"
echo ""
# Check gh auth
if ! gh auth status &>/dev/null; then
echo "⚠️ GitHub CLI not authenticated"
echo "Run: gh auth login"
exit 1
fi
echo "✓ GitHub CLI authenticated"
echo ""
# Setup secrets
echo "═══════════════════════════════════════════════════════════════"
echo " OPTIONAL: Add API keys for AI-powered analysis"
echo " (Skip any you don't want - security scans work without them)"
echo "═══════════════════════════════════════════════════════════════"
echo ""
read -p "Add Gemini API key? (1500 req/day free) [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Get key at: https://aistudio.google.com/apikey"
gh secret set GEMINI_API_KEY
fi
read -p "Add Groq API key? (14,400 req/day free) [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Get key at: https://console.groq.com/keys"
gh secret set GROQ_API_KEY
fi
read -p "Add Mistral API key? (1M tokens/month free) [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Get key at: https://console.mistral.ai/"
gh secret set MISTRAL_API_KEY
fi
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo " ✅ SETUP COMPLETE"
echo "═══════════════════════════════════════════════════════════════"
echo ""
echo "Your fork is now part of the distributed compute network!"
echo ""
echo "What happens now:"
echo " • Security scans run automatically (Semgrep, Trivy, Gitleaks)"
echo " • AI analysis runs on your PRs (using your free tier)"
echo " • You can verify others' work: core issues --label agent:review"
echo ""
echo "The compute you contribute helps fix security issues in"
echo "unfunded open source projects. Thank you! 🙏"
echo ""
echo "Questions? https://discord.gg/host-uk"

View file

@ -27,9 +27,25 @@ if ($PSVersionTable.PSVersion.Major -lt 4) {
}
$Repo = "host-uk/core"
$Version = "v0.1.0" # Pinned version - update when releasing new versions
$MinDiskSpaceMB = 100 # Minimum required disk space in MB
# Resolve latest release version from GitHub API
function Get-LatestVersion {
try {
if (Test-Command gh) {
$version = gh release view --repo $Repo --json tagName -q '.tagName' 2>$null
if ($version) { return $version }
}
# Fallback to GitHub API
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -UseBasicParsing
if ($response.tag_name) { return $response.tag_name }
} catch {
Write-Warn "Could not determine latest version, using default branch"
}
return $null
}
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 }
@ -144,7 +160,7 @@ function New-SecureDirectory {
# Check parent directory for symlinks first
$parent = Split-Path $Path -Parent
if ($parent -and (Test-Path $parent)) {
Test-SecureDirectory -Path $parent
$null = Test-SecureDirectory -Path $parent
}
# Create directory
@ -153,7 +169,7 @@ function New-SecureDirectory {
}
# Immediately verify it's not a symlink (minimize TOCTOU window)
Test-SecureDirectory -Path $Path
$null = Test-SecureDirectory -Path $Path
return $Path
}
@ -181,10 +197,12 @@ function Set-SecureDirectoryAcl {
# Add full control for current user only
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
# Pre-calculate flags to avoid -bor compatibility issues across PowerShell versions
$inheritFlags = [System.Security.AccessControl.InheritanceFlags]([int][System.Security.AccessControl.InheritanceFlags]::ContainerInherit + [int][System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$currentUser,
[System.Security.AccessControl.FileSystemRights]::FullControl,
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit,
$inheritFlags,
[System.Security.AccessControl.PropagationFlags]::None,
[System.Security.AccessControl.AccessControlType]::Allow
)
@ -211,18 +229,18 @@ function Set-SecureDirectoryAcl {
# Download pre-built binary with integrity verification
function Download-Binary {
$arch = if ([Environment]::Is64BitOperatingSystem) { "amd64" } else { "386" }
$binaryUrl = "https://github.com/$Repo/releases/download/$Version/core-windows-$arch.exe"
$checksumUrl = "https://github.com/$Repo/releases/download/$Version/checksums.txt"
$binaryUrl = "https://github.com/$Repo/releases/latest/download/core-windows-$arch.exe"
$checksumUrl = "https://github.com/$Repo/releases/latest/download/checksums.txt"
Write-Info "Attempting to download pre-built binary (version $Version)..."
Write-Info "Attempting to download pre-built binary..."
Write-Info "URL: $binaryUrl"
# Track temp file for cleanup
$tempExe = $null
try {
# Create and verify install directory
New-SecureDirectory -Path $InstallDir
# Create and verify install directory (suppress output to avoid polluting return value)
$null = New-SecureDirectory -Path $InstallDir
# Use a temp file in the same directory (same filesystem for atomic move)
$tempExe = Join-Path $InstallDir "core.exe.tmp.$([System.Guid]::NewGuid().ToString('N').Substring(0,8))"
@ -252,7 +270,7 @@ function Download-Binary {
Test-FileHash -FilePath $tempExe -ExpectedHash $expectedHash
# Re-verify directory hasn't been replaced with symlink (reduce TOCTOU window)
Test-SecureDirectory -Path $InstallDir
$null = Test-SecureDirectory -Path $InstallDir
# Atomic move to final location (same filesystem)
$finalPath = Join-Path $InstallDir "core.exe"
@ -297,13 +315,19 @@ function Test-GitTagSignature {
Push-Location $RepoPath
try {
# Attempt to verify the tag signature
$result = git tag -v $Tag 2>&1
if ($LASTEXITCODE -eq 0) {
# Use $ErrorActionPreference temporarily to prevent stderr from throwing
$oldErrorAction = $ErrorActionPreference
$ErrorActionPreference = "Continue"
$result = git tag -v $Tag 2>&1 | Out-String
$exitCode = $LASTEXITCODE
$ErrorActionPreference = $oldErrorAction
if ($exitCode -eq 0) {
Write-Info "GPG signature verified for tag $Tag"
return $true
} else {
# Check if tag is unsigned vs signature invalid
if ($result -match "error: no signature found") {
if ($result -match "no signature found" -or $result -match "cannot verify a non-tag") {
Write-Warn "Tag $Tag is not signed - continuing without signature verification"
return $true
} else {
@ -326,37 +350,72 @@ function Build-FromSource {
# Create secure temp directory with restrictive ACL
$tmpdir = Join-Path ([System.IO.Path]::GetTempPath()) "core-build-$([System.Guid]::NewGuid().ToString('N'))"
New-SecureDirectory -Path $tmpdir
$null = New-SecureDirectory -Path $tmpdir
# ACL is REQUIRED for temp build directories (security critical)
Set-SecureDirectoryAcl -Path $tmpdir -Required
$null = Set-SecureDirectoryAcl -Path $tmpdir -Required
try {
Write-Info "Cloning $Repo (version $Version)..."
$cloneDir = Join-Path $tmpdir "Core"
# Clone specific tag for reproducibility
git clone --depth 1 --branch $Version "https://github.com/$Repo.git" $cloneDir
if ($LASTEXITCODE -ne 0) {
Write-Err "Failed to clone repository at version $Version"
# Resolve latest version for reproducible builds
$version = Get-LatestVersion
if ($version) {
Write-Info "Resolved latest version: $version"
} else {
Write-Warn "Building from default branch (version unknown)"
}
# Verify GPG signature on tag (if available)
Test-GitTagSignature -RepoPath $cloneDir -Tag $Version
Write-Info "Cloning $Repo..."
$cloneDir = Join-Path $tmpdir "Core"
# Clone specific version if available, otherwise default branch
if ($version) {
git clone --depth 1 --branch $version "https://github.com/$Repo.git" $cloneDir
} else {
git clone --depth 1 "https://github.com/$Repo.git" $cloneDir
}
if ($LASTEXITCODE -ne 0) {
Write-Err "Failed to clone repository"
}
Write-Info "Building core CLI..."
Push-Location $cloneDir
try {
go build -o core.exe .
if ($LASTEXITCODE -ne 0) {
# Explicitly set GOOS/GOARCH to ensure Windows build
$env:GOOS = "windows"
$env:GOARCH = "amd64"
$oldErrorAction = $ErrorActionPreference
$ErrorActionPreference = "Continue"
$buildOutput = go build -o core.exe . 2>&1 | Out-String
$buildExitCode = $LASTEXITCODE
$ErrorActionPreference = $oldErrorAction
if ($buildExitCode -ne 0) {
# Check for Windows-specific build issues
if ($buildOutput -match "Setpgid|Getpgid|syscall\.Kill|undefined.*syscall") {
Write-Warn "Build failed: core CLI uses Unix-specific syscalls not available on Windows."
Write-Warn ""
Write-Warn "Options:"
Write-Warn " 1. Wait for pre-built Windows binaries in GitHub releases"
Write-Warn " 2. Use WSL (Windows Subsystem for Linux) for development"
Write-Warn " 3. Work directly with composer in packages/ (core CLI is optional)"
Write-Warn ""
Write-Warn "For PHP development, you can use composer directly:"
Write-Warn " cd packages/core-php && composer test"
Write-Host ""
# Don't use Write-Err here - exit gracefully
exit 0
} else {
Write-Host $buildOutput
Write-Err "Go build failed"
}
}
} finally {
Pop-Location
}
# Create and verify install directory
New-SecureDirectory -Path $InstallDir
$null = New-SecureDirectory -Path $InstallDir
# Move built binary to install location
Move-Item (Join-Path $cloneDir "core.exe") (Join-Path $InstallDir "core.exe") -Force
@ -424,10 +483,10 @@ function Verify {
# Main
function Main {
Write-Info "Installing Core CLI (version $Version)..."
Write-Info "Installing Core CLI..."
# Check disk space before starting
Test-DiskSpace -Path $InstallDir
$null = Test-DiskSpace -Path $InstallDir
# Try download first, fallback to build
if (-not (Download-Binary)) {

View file

@ -21,10 +21,24 @@ set -e
# - No TLS certificate pinning (relies on system CA store)
REPO="host-uk/core"
VERSION="v0.1.0" # Pinned version - update when releasing new versions
VERSION="${CORE_VERSION:-latest}" # Use latest release, or set CORE_VERSION=dev for dev builds
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
BUILD_FROM_SOURCE="${BUILD_FROM_SOURCE:-auto}"
# Resolve "latest" to actual release tag
resolve_version() {
if [[ "$VERSION" == "latest" ]]; then
if has gh; then
VERSION=$(gh release view --repo "$REPO" --json tagName -q '.tagName' 2>/dev/null) || VERSION="dev"
elif has curl; then
VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null | grep '"tag_name"' | head -1 | cut -d'"' -f4) || VERSION="dev"
else
VERSION="dev"
fi
info "Resolved latest version: $VERSION"
fi
}
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
@ -75,7 +89,8 @@ verify_hash() {
actual_hash=$(compute_sha256 "$file")
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
# Case-insensitive compare (bash 3 compatible)
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
rm -f "$file"
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash. The downloaded file may be corrupted or tampered with."
fi
@ -282,6 +297,7 @@ verify() {
}
main() {
resolve_version
info "Installing Core CLI (version $VERSION)..."
# Verify install directory is safe before starting

View file

@ -102,6 +102,28 @@ function Main {
}
Write-Info "Dependencies installed!"
Write-Host ""
# Configure GitHub CLI if not already authenticated
if (Test-Command gh) {
$authStatus = gh auth status 2>&1 | Out-String
if ($authStatus -match "not logged in") {
Write-Info "Configuring GitHub CLI..."
Write-Host "You'll need to authenticate with GitHub."
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
} else {
# Check for missing scopes
$missingScopes = @()
if ($authStatus -notmatch "workflow") { $missingScopes += "workflow" }
if ($authStatus -notmatch "read:project") { $missingScopes += "read:project,project" }
if ($missingScopes.Count -gt 0) {
Write-Warn "GitHub CLI missing scopes: $($missingScopes -join ', ')"
Write-Host "Run: gh auth refresh -h github.com -s workflow,read:project,project"
}
}
}
Write-Host ""
Write-Host "Next: Run '.\scripts\install-core.ps1' to install the core CLI"
}

View file

@ -44,7 +44,8 @@ verify_hash() {
actual_hash=$(compute_sha256 "$file")
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
# Case-insensitive compare (bash 3 compatible)
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
rm -f "$file"
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash"
fi
@ -286,6 +287,35 @@ main() {
esac
info "Dependencies installed!"
echo ""
# Configure GitHub CLI if not already authenticated
if has gh; then
if ! gh auth status &>/dev/null; then
info "Configuring GitHub CLI..."
echo "You'll need to authenticate with GitHub."
echo "When prompted, select HTTPS and add the 'workflow' scope."
echo ""
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
else
# Check if required scopes are present
local auth_status=$(gh auth status 2>&1)
local missing_scopes=""
if ! echo "$auth_status" | grep -q workflow; then
missing_scopes="workflow"
fi
if ! echo "$auth_status" | grep -q "read:project"; then
missing_scopes="$missing_scopes read:project project"
fi
if [[ -n "$missing_scopes" ]]; then
warn "GitHub CLI missing scopes:$missing_scopes"
echo "Run: gh auth refresh -h github.com -s workflow,read:project,project"
fi
fi
fi
echo ""
echo "Next: Run './scripts/install-core.sh' to install the core CLI"
}