refactor: rename hub-guide → code-guide, remove project-specific content

- Rename all references from hub-guide to code-guide
- Remove project-specific hub-guide skill (100% Asepharyana Hub specific)
- Genericize examples in monorepo, docker, ci-cd, engineering-principles skills
- Use generic service names (frontend, api, worker instead of hub, scraper)
- Use generic registry paths instead of ghcr.io/asepharyana/asepharyana-hub
- Remove project-specific deployment and infrastructure references
This commit is contained in:
asepharyana
2026-07-26 12:28:25 +07:00
parent fa2f1fe838
commit 8bcccfc022
9 changed files with 71 additions and 257 deletions
+14 -42
View File
@@ -1,10 +1,10 @@
# hub-guide — Comprehensive Programming Best-Practice Plugin # code-guide — Comprehensive Programming Best-Practice Plugin
A Claude Code plugin serving as a complete engineering guide for **all programming situations** — monorepo, standalone, any language, any framework. A Claude Code plugin serving as a complete engineering guide for **all programming situations** — monorepo, standalone, any language, any framework.
## Features ## Features
### 🧠 24 Best-Practice Skills ### 24 Best-Practice Skills
| Category | Skills | | Category | Skills |
|----------|--------| |----------|--------|
@@ -13,27 +13,21 @@ A Claude Code plugin serving as a complete engineering guide for **all programmi
| **Frameworks** | react-frontend, elysiajs, hono-backend, drizzle-database, nextjs | | **Frameworks** | react-frontend, elysiajs, hono-backend, drizzle-database, nextjs |
| **Infrastructure** | docker, ci-cd, monitoring | | **Infrastructure** | docker, ci-cd, monitoring |
| **Monorepo** | monorepo (patterns + submodules + workspace tooling) | | **Monorepo** | monorepo (patterns + submodules + workspace tooling) |
| **Hub-specific** | hub-guide (Asepharyana Hub monorepo infra & workflow) |
Skills activate automatically when Claude detects relevant context (language, framework, topic). Skills activate automatically when Claude detects relevant context (language, framework, topic).
### Hooks for Auto-Detection ### Hooks for Auto-Activation
| Hook | Trigger | What It Does | | Hook | Trigger | What It Does |
|------|---------|--------------| |------|---------|--------------|
| **SessionStart** | Session begins | Detects project type from files (package.json, Cargo.toml, go.mod, etc.) and activates relevant skills | | **Stop** | Before stopping | Verifies mandatory skills are being applied (engineering-principles, clean-code, clean-architecture, testing, error-handling, security, git-workflow, api-design) |
| **PreToolUse** | Before Write/Edit | Detects file extension and injects language-specific best-practice rules |
## Installation ## Installation
### Quick Install ### Quick Install
```bash ```bash
# Clone # From anywhere with access to the plugin directory
git clone https://github.com/asepharyana/asepharyana-hub-hub-guide.git
cd asepharyana-hub-hub-guide
# Install as one unit (recommended)
./install.sh ./install.sh
# Or symlink (edits in this repo are live) # Or symlink (edits in this repo are live)
@@ -49,37 +43,19 @@ Example triggers:
- *"Write a test for this"* → `testing` activates - *"Write a test for this"* → `testing` activates
- *"Design an API endpoint"* → `api-design` activates - *"Design an API endpoint"* → `api-design` activates
- Working with `.ts` files → `typescript` activates - Working with `.ts` files → `typescript` activates
- Project with `Cargo.toml``rust` activates (SessionStart hook) - Project with `Cargo.toml``rust` activates
## Auto-Detection (Hooks)
When you start a session in a project, the SessionStart hook scans for:
| File | Skills Activated |
|------|-----------------|
| `tsconfig.json` | typescript, react-frontend, elysiajs, hono-backend, drizzle-database |
| `Cargo.toml` | rust |
| `go.mod` | go |
| `pyproject.toml` | python |
| `pnpm-workspace.yaml` | monorepo |
| `Dockerfile` | docker |
| `.github/workflows/` | ci-cd |
## Structure ## Structure
``` ```
hub-guide/ code-guide/
├── .claude-plugin/ ├── .claude-plugin/
│ └── plugin.json # Plugin manifest │ └── plugin.json # Plugin manifest
├── hooks/ ├── hooks/
── hooks.json # Hook configuration ── hooks.json # Hook configuration (Stop prompt)
│ └── scripts/
│ ├── detect-project.sh # SessionStart auto-detection
│ └── detect-file-type.sh # PreToolWrite language detection
├── skills/ ├── skills/
│ ├── clean-code/ # +23 more skill directories │ ├── clean-code/ # 23 more skill directories
── ... ── ...
│ └── hub-guide/ # Existing hub monorepo guide
└── README.md └── README.md
``` ```
@@ -87,11 +63,7 @@ hub-guide/
Skills are in `skills/<name>/SKILL.md` format (modern Claude Code plugin convention). Each skill includes: Skills are in `skills/<name>/SKILL.md` format (modern Claude Code plugin convention). Each skill includes:
- **Frontmatter** — `name` and `description` with specific trigger phrases - **Frontmatter** — `name` and `description` with trigger context
- **Lean body** — key rules, examples, and anti-patterns (~1500-2000 words) - **Lean body** — key rules, examples, and anti-patterns
Hooks use bash scripts. Edits to hooks/scripts/ take effect immediately when installed as a symlink. The Stop hook injects reminders when mandatory skills aren't being applied.
## Related
Based on patterns from [kana-best-practice-engineering](https://github.com/asepharyana/kana-best-practice-engineering).
+19 -68
View File
@@ -1,82 +1,33 @@
# install.ps1 — hub-guide plugin installer for Claude Code (Windows) # install.ps1 — code-guide plugin installer for Claude Code (Windows)
# #
# Usage: # Usage:
# .\install.ps1 # Install to %USERPROFILE%\.claude\plugins\ # .\install.ps1 # Install to %USERPROFILE%\.claude\skills\
# .\install.ps1 -Project # Install to .claude\plugins\ (project-scoped) # .\install.ps1 -Link # Symlink (PowerShell Admin/Dev mode)
# .\install.ps1 -Link # Symlink (PowerShell Admin/Dev mode)
# .\install.ps1 -NoHooks # Skills only
# .\install.ps1 clean-code testing # Install specific skills
param( param(
[switch]$Project, [switch]$Link
[switch]$Link,
[switch]$NoHooks,
[Parameter(Position=0, ValueFromRemainingArguments=$true)]
[string[]]$SkillFilter
) )
$PluginName = "hub-guide" $PluginName = "code-guide"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$TargetDir = Join-Path $env:USERPROFILE ".claude\skills"
# Determine target
if ($Project) {
$TargetDir = Join-Path (Get-Location) ".claude\plugins"
} else {
$TargetDir = Join-Path $env:USERPROFILE ".claude\plugins"
}
$PluginDir = Join-Path $TargetDir $PluginName $PluginDir = Join-Path $TargetDir $PluginName
Write-Host "📐 hub-guide installer" -ForegroundColor Cyan Write-Host "code-guide installer" -ForegroundColor Cyan
# Ensure target exists New-Item -ItemType Directory -Force -Path $TargetDir | Out-Null
New-Item -ItemType Directory -Force -Path $PluginDir | Out-Null
# Install manifest
Copy-Item -Path (Join-Path $ScriptDir ".claude-plugin") -Destination $PluginDir -Recurse -Force
# Install hooks
if (-not $NoHooks) {
Write-Host " hooks/ → $PluginDir\hooks\"
if ($Link) {
New-Item -ItemType SymbolicLink -Path "$PluginDir\hooks" -Target (Join-Path $ScriptDir "hooks") -Force | Out-Null
} else {
Copy-Item -Path (Join-Path $ScriptDir "hooks") -Destination $PluginDir -Recurse -Force
}
}
# Install skills
if ($SkillFilter.Count -gt 0) {
$SkillDir = Join-Path $PluginDir "skills"
New-Item -ItemType Directory -Force -Path $SkillDir | Out-Null
foreach ($skill in $SkillFilter) {
$skillName = Split-Path $skill -Leaf
$src = Join-Path $ScriptDir "skills" $skillName
if (Test-Path $src) {
Write-Host " skills/$skillName/ → $SkillDir"
if ($Link) {
New-Item -ItemType SymbolicLink -Path (Join-Path $SkillDir $skillName) -Target $src -Force | Out-Null
} else {
Copy-Item -Path $src -Destination $SkillDir -Recurse -Force
}
} else {
Write-Host " ⚠️ Skill '$skillName' not found at $src" -ForegroundColor Yellow
}
}
} else {
Write-Host " skills/ (all) → $PluginDir\skills\"
if ($Link) {
New-Item -ItemType SymbolicLink -Path (Join-Path $PluginDir "skills") -Target (Join-Path $ScriptDir "skills") -Force | Out-Null
} else {
Copy-Item -Path (Join-Path $ScriptDir "skills") -Destination $PluginDir -Recurse -Force
}
}
Write-Host ""
Write-Host "✅ hub-guide installed to $PluginDir" -ForegroundColor Green
if ($Link) { if ($Link) {
Write-Host " (symlink — edits in this repo are live)" Write-Host " symlink mode"
Remove-Item -Path $PluginDir -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType SymbolicLink -Path $PluginDir -Target $ScriptDir -Force | Out-Null
Write-Host " (symlink — edits in this repo are live)"
} else {
Write-Host " copy mode"
Remove-Item -Path $PluginDir -Recurse -Force -ErrorAction SilentlyContinue
Copy-Item -Path $ScriptDir -Destination $PluginDir -Recurse -Force
} }
Write-Host "" Write-Host ""
Write-Host " Restart Claude Code or run /reload to activate." Write-Host "Done. Restart Claude Code or run /reload."
Write-Host " Skills auto-trigger when you work — no commands needed." Write-Host "Skills auto-trigger. Hooks auto-load from hooks/hooks.json."
+4 -4
View File
@@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
# install.sh — hub-guide installer for Claude Code # install.sh — code-guide installer for Claude Code
# Installs the entire hub-guide directory as one unit into ~/.claude/skills/. # Installs the entire code-guide directory as one unit into ~/.claude/skills/.
# Skills auto-discover, hooks auto-load from hooks/hooks.json. # Skills auto-discover, hooks auto-load from hooks/hooks.json.
# Usage: # Usage:
# ./install.sh # Copy hub-guide to ~/.claude/skills/ # ./install.sh # Copy code-guide to ~/.claude/skills/
# ./install.sh --link # Symlink (edits live) # ./install.sh --link # Symlink (edits live)
# Requires: Claude Code # Requires: Claude Code
@@ -25,7 +25,7 @@ echo " target: ${SKILLS_DIR}/code-guide/"
echo " mode: $([ "$LINK_MODE" = true ] && echo 'symlink' || echo 'copy')" echo " mode: $([ "$LINK_MODE" = true ] && echo 'symlink' || echo 'copy')"
mkdir -p "$SKILLS_DIR" mkdir -p "$SKILLS_DIR"
DST="${SKILLS_DIR}/hub-guide" DST="${SKILLS_DIR}/code-guide"
if [ "$LINK_MODE" = true ]; then if [ "$LINK_MODE" = true ]; then
rm -rf "$DST" rm -rf "$DST"
+5 -5
View File
@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# setup-hooks.sh — Configure hub-guide hooks in Claude Code # setup-hooks.sh — Configure code-guide hooks in Claude Code
# #
# Adds hub-guide hooks to ~/.claude/settings.local.json # Adds code-guide hooks to ~/.claude/settings.local.json
# This allows Claude to auto-detect your project and suggest relevant skills. # This allows Claude to auto-detect your project and suggest relevant skills.
# #
# Usage: ./setup-hooks.sh # Usage: ./setup-hooks.sh
@@ -11,7 +11,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SETTINGS_FILE="${HOME}/.claude/settings.local.json" SETTINGS_FILE="${HOME}/.claude/settings.local.json"
echo "📐 hub-guide hooks setup" echo "code-guide hooks setup"
python3 << PYEOF python3 << PYEOF
import json, os import json, os
@@ -51,8 +51,8 @@ os.makedirs(os.path.dirname(settings_file), exist_ok=True)
with open(settings_file, 'w') as f: with open(settings_file, 'w') as f:
json.dump(cfg, f, indent=2) json.dump(cfg, f, indent=2)
print(f"Hooks configured in {settings_file}") print(f"Hooks configured in {settings_file}")
PYEOF PYEOF
echo "" echo ""
echo " Restart Claude Code or run /reload to activate hooks." echo "Restart Claude Code or run /reload to activate hooks."
+8 -8
View File
@@ -55,16 +55,16 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
service: [scraper, hub] service: [frontend, api]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: | - run: |
docker build \ docker build \
-f infra/docker/${{ matrix.service }}.Dockerfile \ -f infra/docker/${{ matrix.service }}.Dockerfile \
-t ghcr.io/.../${{ matrix.service }}:sha-${{ github.sha }} \ -t ghcr.io/myorg/myproject/${{ matrix.service }}:sha-${{ github.sha }} \
-t ghcr.io/.../${{ matrix.service }}:latest \ -t ghcr.io/myorg/myproject/${{ matrix.service }}:latest \
. .
- run: docker push --all-tags ghcr.io/.../${{ matrix.service }} - run: docker push --all-tags ghcr.io/myorg/myproject/${{ matrix.service }}
``` ```
**Deploy (after build)** **Deploy (after build)**
@@ -101,7 +101,7 @@ jobs:
build: build:
strategy: strategy:
matrix: matrix:
service: [scraper, hub, api] service: [frontend, api, worker]
fail-fast: false # Let others complete even if one fails fail-fast: false # Let others complete even if one fails
``` ```
@@ -149,10 +149,10 @@ secrets:
6. **Security scan** (<5 min) — CodeQL, dependency audit, secret scan 6. **Security scan** (<5 min) — CodeQL, dependency audit, secret scan
7. **Deploy** (<2 min) — SSH, pull, restart 7. **Deploy** (<2 min) — SSH, pull, restart
## Deployment (this repo's pattern) ## Deployment Pattern
1. SSH to VPS (`orangevps`) 1. SSH to deployment target
2. Pull latest images from GHCR 2. Pull latest images from container registry
3. Restart specific container (not all) 3. Restart specific container (not all)
4. Health check after restart 4. Health check after restart
5. Rollback if health check fails 5. Rollback if health check fails
+10 -12
View File
@@ -76,12 +76,11 @@ networks:
external: true external: true
``` ```
### Typical Services Layout (this repo) ### Typical Docker Compose Order
- **Redis:** `shared.yml`always first - **Data layer:** `db.yml`, `redis.yml`stateful services first
- **NATS:** `nats.yml` — JetStream-enabled - **Messaging:** `nats.yml`, `rabbitmq.yml` — message brokers
- **Dapr:** `dapr.yml` — placement service - **Infrastructure:** `traefik.yml`, `nginx.yml` — reverse proxy
- **Traefik:** `traefik.yml` — reverse proxy - **Application:** `app.yml` — service containers
- **App + Sidecar:** `app.yml` — service + daprd sidecar
## Security ## Security
@@ -99,17 +98,16 @@ networks:
sha-<short-sha> # Immutable — for deterministic rollbacks sha-<short-sha> # Immutable — for deterministic rollbacks
latest # Mutable — convenience latest # Mutable — convenience
# Example (from this repo's CI) # Example
ghcr.io/asepharyana/asepharyana-hub/<service>:sha-a1b2c3d ghcr.io/myorg/myproject/<service>:sha-a1b2c3d
ghcr.io/asepharyana/asepharyana-hub/<service>:latest ghcr.io/myorg/myproject/<service>:latest
``` ```
## Networking ## Networking
- **All containers** join `app-shared-net` (external Docker bridge). - **All containers** join the same Docker network (external bridge).
- **DNS resolution** via Docker DNS (container name = hostname). - **DNS resolution** via Docker DNS (container name = hostname).
- **Cross-VPS** via Tailscale (`100.64.0.0/10`). - **Expose only needed ports** — reverse proxy handles external traffic on port 443.
- **Expose only needed ports** — Traefik handles external traffic on port 443.
## Debugging ## Debugging
+1 -1
View File
@@ -312,4 +312,4 @@ Never guess, speculate, or assume. **Every claim, suggestion, or piece of code y
✅ "I searched for .env and didn't find one. There's a .env.example — maybe that's the template. Could you check?" ✅ "I searched for .env and didn't find one. There's a .env.example — maybe that's the template. Could you check?"
❌ "Dockerfiles are usually in the root" ❌ "Dockerfiles are usually in the root"
✅ "I found the Dockerfile at: infra/docker/hub.Dockerfile" ✅ "I found the Dockerfile at: infra/docker/app.Dockerfile"
-107
View File
@@ -1,107 +0,0 @@
---
name: hub-guide
description: Guide for the Asepharyana Hub monorepo — submodule workflow, infrastructure stack (Traefik, Dapr, NATS, Redis), CI/CD pipelines, adding new services, and debugging tips. Use when working in the asepharyana-hub monorepo, managing submodules, dealing with Docker/infra setup. Detects from code context and project files — not dependent on specific language keywords."
---
# Hub Guide — Asepharyana Hub Monorepo
## Submodule Workflow
- Code changes go in the submodule repo, not here. The hub monorepo only tracks submodule pointers.
- After pushing changes to a submodule repo, update the pointer here:
```bash
cd apps/<name> && git checkout main && git pull
cd ../.. && git add apps/<name> && git commit -m "chore(deps): update <name> submodule"
```
- CI/CD auto-updates submodule pointers via `repository_dispatch`. Manual updates are fine for dev.
### Typical Submodule State
| State | Meaning |
|-------|---------|
| `(HEAD)` | Detached HEAD — submodule is at the committed pointer |
| `(main)` | On the default branch — you've done `cd apps/name && git checkout main` |
| Dirty | Uncommitted changes inside submodule |
To reset a submodule to its committed pointer:
```bash
git submodule update --init --recursive apps/<name>
```
## Development Quickstart
```bash
make init-submodules # After fresh clone — fetches all submodules
make dev # Start Redis for local dev
docker compose -f infra/compose/shared.yml up -d # Full infra stack
```
## Local vs Production
| Aspect | Local | Production (VPS) |
|--------|-------|------------------|
| DB | None (or local) | PostgreSQL on `imrnes` via Tailscale |
| Redis | `make dev` | Container on `orangevps` |
| Traefik | Not running | TLS-terminated on `orangevps` |
| DNS | `localhost` | `*.asepharyana.my.id`, `*.asepharya.web.id` |
## Debugging Tips
### Docker compose validation
```bash
for f in infra/compose/*.yml; do docker compose -f "$f" config >/dev/null && echo "OK $f"; done
```
### YAML syntax check
```bash
python -c "import pathlib, yaml; [yaml.safe_load(open(p)) for p in pathlib.Path('infra').rglob('*.yml')]"
```
### Check submodule pointers
```bash
git submodule status
# Leading `-` = not initialized, `+` = different from committed hash, ` ` = matches
```
### Traefik route not working?
1. Check `infra/traefik/dynamic/apps.yaml` — router rule + service definition present?
2. Container labels in compose file include Traefik config?
3. Container on `app-shared-net`?
## Adding a New Service — Checklist
1. [ ] Create separate repo for app code
2. [ ] `git submodule add <url> apps/<name>`
3. [ ] Create Dockerfile in `infra/docker/`
4. [ ] Create compose file in `infra/compose/` (app + Dapr sidecar)
5. [ ] Add Traefik router in `infra/traefik/dynamic/apps.yaml`
6. [ ] Add build job in `.github/workflows/docker-build-push.yml`
7. [ ] Verify: `docker compose -f infra/compose/<name>.yml config`
See `docs/add-new-app.md` for full guide.
## Monitoring
- **Dashboard**: `/dashboard` on the hub site (auto-refresh 15s)
- **Dashboard API**: `/api/dashboard` — JSON with containers, traces, metrics
- **Prometheus**: Auto-discovers containers with `prometheus.io/scrape=true` label via Docker SD
- **Jaeger**: Traces via OTLP — check for cross-service latency
## Infrastructure Files Map
| Path | Purpose |
|------|---------|
| `infra/compose/*.yml` | One Docker Compose file per service |
| `infra/dapr/components/` | Dapr pub/sub, state store component configs |
| `infra/docker/*.Dockerfile` | Build files per service |
| `infra/traefik/dynamic/apps.yaml` | Traefik route definitions |
| `infra/traefik/traefik.yml` | Traefik static config (entrypoints, providers) |
| `.github/workflows/` | CI/CD pipelines |
| `docs/` | ADRs, deployment guide, new-app guide |
## Git Hook Scripts
Located in `scripts/`:
- `scripts/cleanup.sh` — prune old Docker images, clean temp files
- `scripts/update-deps.sh` — bump dependencies across submodules
- `scripts/setup-hooks.sh` — install local git hooks
+10 -10
View File
@@ -19,8 +19,8 @@ description: Monorepo best practices — tooling, workspace configuration, share
``` ```
├── apps/ ├── apps/
│ ├── hub/ # Next.js app (submodule) │ ├── app1/ # Application (submodule)
│ └── scraper/ # Rust API (submodule) │ └── app2/ # Another application (submodule)
├── packages/ # Shared libraries (when not submodules) ├── packages/ # Shared libraries (when not submodules)
├── infra/ # Shared infra config ├── infra/ # Shared infra config
├── pnpm-workspace.yaml ├── pnpm-workspace.yaml
@@ -61,13 +61,13 @@ pnpm -r run build
- **Explicit `dependencies`** — never rely on hoisting. - **Explicit `dependencies`** — never rely on hoisting.
- **Lock file** (`pnpm-lock.yaml`) committed — immutable installs. - **Lock file** (`pnpm-lock.yaml`) committed — immutable installs.
## Git Submodules (this repo's pattern) ## Git Submodules
``` ```
asepharyana-hub/ my-monorepo/
├── apps/ ├── apps/
│ ├── hub/ → asepharyana/asepharyana-hub-hub │ ├── app1/ → org/app1-repo
│ └── scraper/ → asepharyana/asepharyana-hub-scraper │ └── app2/ → org/app2-repo
``` ```
### Submodule Workflow ### Submodule Workflow
@@ -79,8 +79,8 @@ git submodule update --init --recursive
git submodule foreach git pull origin main git submodule foreach git pull origin main
# Update one submodule # Update one submodule
cd apps/hub && git checkout main && git pull cd apps/app1 && git checkout main && git pull
cd ../.. && git add apps/hub && git commit -m "chore(deps): update hub submodule" cd ../.. && git add apps/app1 && git commit -m "chore(deps): update app1 submodule"
git push git push
``` ```
@@ -107,8 +107,8 @@ on:
push: push:
branches: [main] branches: [main]
paths: paths:
- 'apps/hub/**' - 'apps/app1/**'
- 'infra/docker/hub.Dockerfile' - 'infra/docker/app1.Dockerfile'
``` ```
### Affected Commands (Nx/Turborepo/Moon) ### Affected Commands (Nx/Turborepo/Moon)