Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 23 additions & 41 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,57 +75,39 @@ jobs:

VERSION="${BRANCH#release/v}"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
echo "TAG=v$VERSION" >> "$GITHUB_ENV"

- name: Checkout PR branch
uses: actions/checkout@v5
- name: Merge PR into main
run: |
gh pr merge ${{ env.PR_NUMBER }} \
--merge \
--admin \
--repo ${{ github.repository }}

- name: Checkout main
uses: actions/checkout@v4
with:
ref: ${{ env.PR_BRANCH }}
ref: main
fetch-depth: 0
# NOTE: If branch protection requires signed commits, replace with:
# token: ${{ secrets.RELEASE_PAT }}

- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Bump package.json version
run: |
jq --arg v "${{ env.VERSION }}" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json

- name: Commit version bump
run: |
git add package.json
if git diff --cached --quiet; then
echo "Version already at ${{ env.VERSION }}, skipping commit."
else
git commit -m "chore(release): bump version to ${{ env.VERSION }}"
fi

- name: Push to PR branch
run: |
git push origin HEAD:${{ env.PR_BRANCH }}

- name: Merge PR
run: |
gh pr merge ${{ env.PR_NUMBER }} \
--merge \
--repo ${{ github.repository }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Tag merge commit on main
run: |
git fetch origin main
git tag "${{ env.TAG }}" origin/main
git push origin "${{ env.TAG }}"
- name: Install dependencies
run: npm ci

- name: Create GitHub Release
run: |
gh release create "${{ env.TAG }}" \
--title "${{ env.TAG }}" \
--generate-notes \
--repo ${{ github.repository }}
- name: Run release-it
run: npx release-it ${{ env.VERSION }} --ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Delete release branch
run: |
Expand All @@ -136,7 +118,7 @@ jobs:
run: |
gh api repos/${{ github.repository }}/issues/${{ env.PR_NUMBER }}/comments \
--method POST \
--field body="Deployed successfully. Version \`${{ env.VERSION }}\` has been tagged as \`${{ env.TAG }}\`, a GitHub Release has been created with auto-generated release notes, and this PR has been merged into \`main\`."
--field body="Deployed successfully. Version \`${{ env.VERSION }}\` published to npm and released on GitHub."

- name: Post failure comment
if: failure()
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Unit Test

on:
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.claude/
node_modules/
16 changes: 16 additions & 0 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"git": {
"commitMessage": "chore(release): v${version}",
"tagName": "v${version}",
"requireBranch": "main",
"requireCleanWorkingDir": true
},
"github": {
"release": true,
"autoGenerate": true
},
"npm": {
"publish": true,
"access": "public"
}
}
121 changes: 84 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,64 @@
# AIWorkers

Central package for AI configurations. Instead of each project having its own `CLAUDE.md` written from scratch, AIWorkers centralizes everything that is generic. Each project inherits with a single line and only writes what is specific to itself.
[![npm](https://img.shields.io/npm/v/@salve-software/aiworkers)](https://www.npmjs.com/package/@salve-software/aiworkers)

Central npm package for Claude Code configurations. Instead of each project writing its own `CLAUDE.md` from scratch, AIWorkers centralizes everything that is reusable β€” commit standards, slash commands, agent personas, and rules. Each project installs the package and runs one command.

---

## How it works
## Installation

Install globally once per machine:

```bash
npm install -g @salve-software/aiworkers
```

Then run inside each project that should use AIWorkers:

```bash
aiworkers setup
```

Any project creates a `CLAUDE.md` with one line:
Or without installing globally:

```markdown
@../../packages/AIWorkers/CLAUDE.md
```bash
npx @salve-software/aiworkers setup
```

Claude Code automatically injects all AIWorkers context β€” rules, commands, and agent personas. Below the import, the project writes only what is specific to it.
The setup command links commands, skills, agents, and rules from the package into the project's `.claude/` folder, and adds the necessary imports to `.claude/CLAUDE.md`.

---

## CLI

```
AIWorkers v0.2.1
Claude Code configurations for every project

Usage: aiworkers <command>

Commands:

setup Link AIWorkers into the current project's .claude/ folder
--version Print the installed version
--help Show this help message
```

---

## What it sets up

Inside your project's `.claude/`:

```
.claude/
β”œβ”€β”€ commands/aiworkers/ # User-invokable slash commands
β”œβ”€β”€ skills/aiworkers/ # Context-triggered skills (auto-invoked by Claude)
β”œβ”€β”€ agents/aiworkers/ # Agent personas loaded on demand by skills
β”œβ”€β”€ rules/aiworkers/ # Composable rules imported into CLAUDE.md
└── CLAUDE.md # Auto-updated with @rules/aiworkers/* imports
```

---

Expand All @@ -23,52 +69,53 @@ Claude Code automatically injects all AIWorkers context β€” rules, commands, and
| Commit standards | βœ… | |
| Reusable slash commands | βœ… | |
| Agent personas | βœ… | |
| Permissions (`settings.json`) | βœ… | |
| Domain context | | βœ… |
| Specific stack | | βœ… |
| Business rules | | βœ… |
| Project-specific commands | | βœ… |

---

## Structure

```
AIWorkers/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ commands/ # User-invokable slash commands β†’ docs/commands.md
β”‚ β”œβ”€β”€ skills/ # Context-triggered skills (auto-invoked by Claude)
β”‚ β”œβ”€β”€ agents/ # Agent personas β†’ docs/agents.md
β”‚ └── rules/ # Composable rules (one responsibility per file)
β”œβ”€β”€ docs/ # Decisions, patterns, and reference docs
β”œβ”€β”€ scripts/
β”‚ └── setup.sh # Links src/ into .claude/
β”œβ”€β”€ CLAUDE.md
└── settings.json # Source of truth for permissions
```

---

## Setup
## Available commands

Run once per machine:
| Command | Description |
|---|---|
| `/feature` | PDCA multi-agent workflow to plan, implement, review, and ship a feature |
| `/aiworkers:land` | Create branch + commit + PR in one step |
| `/rn-component` | Scaffold a React Native component using the Layered Hook Architecture |

```bash
./scripts/setup.sh
```
Skills (auto-triggered by Claude based on context):

The script symlinks commands, agents, and rules from `src/` into `.claude/`, and keeps `settings.json` in sync. No restart needed after running.
| Skill | Trigger |
|---|---|
| `branch` | When Claude needs to create a git branch |
| `commit` | When the user wants to commit changes |
| `pr` | When the user wants to open a pull request |

---

## Reference
## Requirements

- [Slash commands](docs/commands.md)
- [Agent personas](docs/agents.md)
- Node.js 18+
- Claude Code with an active Pro or Team plan
- `gh` CLI installed and authenticated (required for `/pr` and `/feature`)

---

## Requirements
## Structure

- Claude Code with an active Pro or Team plan
- `gh` CLI installed and authenticated (required for `/pr` and `/feature`)
```
AIWorkers/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ commands/ # User-invokable slash commands
β”‚ β”œβ”€β”€ skills/ # Context-triggered skills
β”‚ β”œβ”€β”€ agents/ # Agent personas
β”‚ └── rules/ # Composable rules
β”œβ”€β”€ bin/
β”‚ └── aiworkers.js # CLI entry point
β”œβ”€β”€ scripts/
β”‚ └── setup.sh # Legacy bash setup (Unix only)
β”œβ”€β”€ docs/ # Decisions, patterns, and reference docs
β”œβ”€β”€ CLAUDE.md
└── package.json
```
40 changes: 40 additions & 0 deletions bin/aiworkers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env node

import { createRequire } from 'module';
import boxen from 'boxen';
import { banner, c } from './banner.js';
import { setup } from './commands/setup.js';

const require = createRequire(import.meta.url);
const pkg = require('../package.json');

const command = process.argv[2];

if (command === 'setup') {
banner();
setup();
} else if (command === '--version' || command === '-v') {
console.log(pkg.version);
} else if (!command || command === '--help' || command === '-h') {
banner();
console.log(boxen(
`${c.bold}Usage:${c.reset} aiworkers <command>\n\n` +
`${c.bold}Commands:${c.reset}\n\n` +
` ${c.cyan}setup${c.reset} Link AIWorkers into the current project's .claude/ folder\n` +
` ${c.cyan}--version${c.reset} Print the installed version\n` +
` ${c.cyan}--help${c.reset} Show this help message\n\n` +
`${c.bold}Example:${c.reset}\n\n` +
` cd my-project\n` +
` aiworkers setup`,
{
padding: 1,
borderStyle: 'round',
borderColor: 'cyan',
dimBorder: true,
}
));
console.log();
} else {
console.error(`\n ${c.yellow}Unknown command:${c.reset} ${command}\n`);
process.exit(1);
}
28 changes: 28 additions & 0 deletions bin/banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import figlet from 'figlet';
import boxen from 'boxen';
import { createRequire } from 'module';

const require = createRequire(import.meta.url);
const pkg = require('../package.json');

export const c = {
reset: '\x1b[0m',
bold: '\x1b[1m',
dim: '\x1b[2m',
green: '\x1b[32m',
cyan: '\x1b[36m',
yellow: '\x1b[33m',
gray: '\x1b[90m',
};

export function banner() {
const ascii = figlet.textSync('AIWorkers', { font: 'Slant' });
const content = `${c.cyan}${ascii}${c.reset}\n ${c.dim}v${pkg.version} Β· Claude Code configurations for every project${c.reset}`;
console.log(boxen(content, {
padding: { top: 0, bottom: 0, left: 1, right: 1 },
borderStyle: 'round',
borderColor: 'cyan',
dimBorder: true,
}));
console.log();
}
Loading
Loading