Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/wbfy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ This tool must keep idempotency, i.e., it always yields the same result when a u
## How to Use

1. `bunx @willbooster/wbfy <project directory>`
2. `bunx @willbooster/wbfy generate-user-agent-instructions` to overwrite your user-level agent instruction files (`~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, `~/.gemini/GEMINI.md`) with the organization's fixed content
29 changes: 29 additions & 0 deletions packages/wbfy/src/generators/userAgentInstructions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os from 'node:os';
import path from 'node:path';

import { fsUtil } from '../utils/fsUtil.js';

/**
* The user-level instruction file of each supported agent, relative to the home directory. These
* apply to every repository the agent works in, so they hold only the conventions that are true on
* every WillBooster developer machine rather than in a particular repository.
*/
const userAgentInstructionFilePaths = ['.codex/AGENTS.md', '.claude/CLAUDE.md', '.gemini/GEMINI.md'] as const;

const userAgentInstructionContent = `- Repos live under \`~/ghq/github.com\`; always clone with \`ghq get -p\`, never \`git clone\`.
- LLM/AI agent responses may take 1–2 hours; wait patiently, don't assume failure.
- No AI attribution (e.g., \`Co-Authored-By\` trailers, "Generated with ..." footers) in commits, issues, or PRs unless explicitly requested. This hides nothing: if asked which AI agent did the work, answer truthfully.
`;

/**
* Overwrites the user-level instruction files of every supported agent with the fixed content.
* Returns false when any file was skipped (e.g. a symlinked file), so the command can fail loudly.
*/
export async function generateUserAgentInstructions(): Promise<boolean> {
let hasWrittenAll = true;
for (const relativePath of userAgentInstructionFilePaths) {
const hasWritten = await fsUtil.generateFile(path.join(os.homedir(), relativePath), userAgentInstructionContent);
hasWrittenAll &&= hasWritten;
}
return hasWrittenAll;
}
11 changes: 11 additions & 0 deletions packages/wbfy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { generateReadme, readAppliedWbfyVersionLabel } from './generators/readme
import { generateReleaserc } from './generators/releaserc.js';
import { generateRenovateJsonc } from './generators/renovateJsonc.js';
import { generateTsconfig } from './generators/tsconfig.js';
import { generateUserAgentInstructions } from './generators/userAgentInstructions.js';
import { generateVscodeSettings } from './generators/vscodeSettings.js';
import { ensureWbEnvDefinitions } from './generators/wbEnv.js';
import { generateSelfContainedWorkflows } from './generators/selfContainedWorkflow.js';
Expand Down Expand Up @@ -58,13 +59,19 @@ import { getWorkspaceSubDirPaths } from './utils/workspaceUtil.js';
* name would swallow a directory that happens to share it.
*/
const applyReleaseAgeGateCommand = 'apply-release-age-gate';
/** Same naming rationale as applyReleaseAgeGateCommand. */
const generateUserAgentInstructionsCommand = 'generate-user-agent-instructions';

async function main(): Promise<void> {
const argv = await yargs(process.argv.slice(2))
.command(
applyReleaseAgeGateCommand,
"Apply only the organization's minimum-release-age policy to this machine's global package-manager configs"
)
.command(
generateUserAgentInstructionsCommand,
"Overwrite this user's agent instruction files (~/.codex/AGENTS.md, ~/.claude/CLAUDE.md, ~/.gemini/GEMINI.md) with the organization's fixed content"
)
.command('$0 [paths..]', 'Make a given project follow the WillBooster standard', (yargs) => {
yargs.positional('paths', {
describe: 'project paths to be wbfied',
Expand Down Expand Up @@ -104,6 +111,10 @@ async function main(): Promise<void> {
if (!ensureGlobalReleaseAgeGates()) process.exitCode = 1;
return;
}
if (argv._[0] === generateUserAgentInstructionsCommand) {
if (!(await generateUserAgentInstructions())) process.exitCode = 1;
return;
}

let hasInvalidPackageConfig = false;
try {
Expand Down
Loading