I like and prefer BUN... AI driftsπ΅βπ«. THIS stops that from happening.
Human and AI-Paired Programming Environments (HAIPPy)
Version: 1.0.0
Created: 2025-10-25
License: CC0 1.0 Universal (Public Domain)
Purpose: Universal guide for enforcing specific tools in AI-assisted development
- Executive Summary
- The Problem Space
- Solution Architecture
- Implementation Guide
- Language & Framework Extensions
- Maintenance & Evolution
- Troubleshooting
- Appendices
HAIPPy (Human and AI-Paired Programming Environments & Ecosystems) is a methodology and collection of various frameworks, for optimal collaboration between Human and AI Paired Entities, across various domains of the SDLC.
This [Package Manager Enforcement Guide], is a design pattern for creating selective barriers that enforce correct tooling choices in codebases where AI agents assist with development.
AI coding assistants often default to common tools (npm, pip, maven) without reading project requirements, potentially:
- Installing wrong package manager dependencies
- Creating incompatible lock files
- Triggering incorrect build processes
- Overriding team standards
Create multi-layered protection systems that:
- β Block incorrect tools (npm, pip, etc.)
- β Allow correct tools (bun, poetry, etc.)
- β Fail fast with clear error messages
- β Require no AI context to work
- β Are human-readable for debugging
Use tool-specific configuration files with divergent registry settings:
- Wrong tool reads invalid config β immediate failure
- Correct tool reads valid config β seamless success
AI agents typically select tools based on:
| Priority | Selection Method | Risk Level |
|---|---|---|
| 1 | File detection (package-lock.json β npm) | π΄ High |
| 2 | Convention (Node.js β npm, Python β pip) | π΄ High |
| 3 | Popularity (npm > bun, pip > poetry) | π‘ Medium |
| 4 | Explicit instructions (README, docs) | π’ Low |
| 5 | Configuration files (.npmrc, pyproject.toml) | π’ Low |
Problem: AI agents often operate at Priority 1-3, missing project-specific requirements.
| Scenario | Wrong Command | Impact |
|---|---|---|
| JS/TS Projects | npm install instead of bun install |
Wrong lock file, slower installs |
| Python Projects | pip install instead of poetry install |
No venv, dependency conflicts |
| Ruby Projects | gem install instead of bundle install |
Wrong versions, global pollution |
| Java Projects | mvn install instead of gradle build |
Different build artifacts |
| Rust Projects | Custom scripts instead of cargo |
Missed optimizations |
| Approach | Why It Fails |
|---|---|
| Documentation alone | AI agents may not read/prioritize docs |
| Lock files | AI agents create wrong lock files |
| Convention | AI agents follow ecosystem defaults |
| Manual reminders | Context windows reset, instructions lost |
| Gitignore | Doesn't prevent creation, only blocks commit |
A successful HAIPPy pattern must:
- β Passive enforcement: Works without AI awareness
- β Fail fast: Errors occur immediately at wrong tool usage
- β Clear feedback: Error messages guide to correct tool
- β Zero ambiguity: Only one tool can succeed
- β No maintenance overhead: Self-documenting, automatic
- β Human-debuggable: Humans can understand and fix issues
The HAIPPy pattern uses defense in depth with four independent layers:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 4: Engine Requirements (package.json engines) β
β Effect: Shows warning/error if wrong runtime version β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β If bypassed
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 3: Tool-Specific Config (.bunfig.toml) β
β Effect: Provides valid configuration for correct tool β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β If wrong tool used
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 2: Runtime Enforcement (enforce-bun.js) β
β Effect: Preinstall hook checks package manager identity β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β If hook bypassed
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 1: Registry Divergence (.npmrc with invalid URL) β
β Effect: Wrong tool fails immediately on registry access β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Principle: Tools read different config files. Make wrong tool's config invalid.
Execution Flow:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User runs: bun install
β
bun looks for: .bunfig.toml (found β)
β
Reads registry: https://registry.npmjs.org/ (valid β)
β
Installation proceeds: SUCCESS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User runs: npm install
β
npm looks for: .npmrc (found β)
β
Reads registry: https://DO-NOT-USE-NPM.invalid/ (INVALID β)
β
Installation fails immediately: ERROR β
β
Error message shown: "Use bun instead"
Key Insight: Configuration files create a selective barrierβthey're read by one tool but not others, allowing precise control over which tool succeeds.
Different package managers read different config files in different orders:
| Tool | Config Files (Priority Order) | HAIPPy Strategy |
|---|---|---|
| npm | .npmrc β package.json | Make .npmrc invalid |
| bun | .bunfig.toml β .npmrc β package.json | Make .bunfig.toml valid |
| yarn | .yarnrc.yml β .npmrc β package.json | Make .yarnrc.yml invalid |
| pnpm | .npmrc β package.json | Make .npmrc invalid (same as npm) |
Implication: By making .npmrc invalid and .bunfig.toml valid, we block npm/yarn/pnpm while allowing bun.
Principle: Check the tool's identity at runtime before executing.
All Node.js-based package managers set npm_config_user_agent:
# Examples of npm_config_user_agent values:
npm/10.2.4 node/v20.11.0 win32 x64 workspaces/false
yarn/1.22.19 npm/? node/v20.11.0 win32 x64
pnpm/8.15.1 npm/? node/v20.11.0 win32 x64
bun/1.2.18 node/v20.11.0 win32 x64Validation Logic:
// Runtime check in preinstall hook
const userAgent = process.env.npm_config_user_agent || '';
if (!userAgent.includes('bun')) {
console.error('β ERROR: Use bun, not npm/yarn/pnpm');
process.exit(1); // Block installation
}
console.log('β
Using bun - proceeding...');The HAIPPy pattern is Mutually Exclusive, Collectively Exhaustive:
| Scenario | Layer 1 (Registry) | Layer 2 (Runtime) | Layer 3 (Config) | Layer 4 (Engine) | Result |
|---|---|---|---|---|---|
| Correct tool (bun) | Skips (uses Layer 3) | β Pass | β Valid config | β Correct version | β SUCCESS |
| Wrong tool (npm) | β Invalid registry | β Blocked | N/A (blocked earlier) | N/A | β BLOCKED |
| npm --no-scripts | β Invalid registry | Skipped (no hook) | N/A | N/A | β BLOCKED |
| Wrong tool version | Skips/passes | β Pass | β Valid config | β Wrong version |
Coverage: All possible tool + flag combinations result in either SUCCESS or BLOCKEDβno ambiguous states.
# .bunfig.toml
# Purpose: Provide valid registry for bun (correct tool)
[install]
registry = "https://registry.npmjs.org/"
cache = true
frozenLockfile = false
peer = "auto"
optional = truePurpose: Give bun a valid configuration so it succeeds.
# .npmrc
# Purpose: Provide INVALID registry for npm/yarn/pnpm (wrong tools)
# INTENTIONALLY BROKEN - DO NOT FIX
registry=https://DO-NOT-USE-NPM-USE-BUN-INSTEAD.invalid/
# Additional breaking configs
package-lock=false
engine-strict=truePurpose: Make npm fail immediately with clear error.
// scripts/enforce-bun.js
// Purpose: Runtime check via preinstall hook
#!/usr/bin/env node
const userAgent = process.env.npm_config_user_agent || '';
if (!userAgent.includes('bun')) {
console.error(`
βββββββββββββββββββββββββββββββββββββ
β ERROR: Wrong Package Manager!
βββββββββββββββββββββββββββββββββββββ
This project requires BUN.
Detected: ${userAgent || 'npm/yarn/pnpm'}
Required: bun
Install bun:
curl -fsSL https://bun.sh/install | bash
Then run:
bun install
βββββββββββββββββββββββββββββββββββββ
`);
process.exit(1);
}
console.log('β Using bun - proceeding...');Purpose: Block wrong tool before any files are created.
{
"name": "your-project",
"packageManager": "[email protected]",
"engines": {
"node": ">=20.0.0",
"bun": ">=1.2.0"
},
"scripts": {
"preinstall": "node scripts/enforce-bun.js",
"postinstall": "bun run validate-environment"
}
}Purpose:
preinstall: Trigger Layer 2 enforcementengines: Layer 4 version requirementspackageManager: Hint to Corepack (optional)
# Should FAIL (wrong tool)
npm install
# Expected: Error from .npmrc (invalid registry)
# Should FAIL (wrong tool, bypass registry)
npm install --registry https://registry.npmjs.org/
# Expected: Error from enforce-bun.js (preinstall hook)
# Should FAIL (wrong tool, no scripts)
npm install --ignore-scripts
# Expected: Error from .npmrc (invalid registry)
# Should SUCCEED (correct tool)
bun install
# Expected: Success with all layers working correctly# poetry.toml
# Purpose: Valid configuration for poetry (correct tool)
[virtualenvs]
in-project = true
create = true
[repositories]
default = "https://pypi.org/simple/"# pip.conf (Linux/Mac: ~/.pip/pip.conf, Windows: %APPDATA%\pip\pip.ini)
# Purpose: Invalid config for pip (wrong tool)
[global]
# INTENTIONALLY BROKEN - DO NOT FIX
index-url = https://DO-NOT-USE-PIP-USE-POETRY-INSTEAD.invalid/pypi/simple/
# Alternative: Make pip require confirmation
require-virtualenv = trueNote: pip.conf is user-level, not project-level. Better approach: use .python-version + enforcement script.
#!/usr/bin/env python3
# scripts/enforce-poetry.py
# Purpose: Block pip, require poetry
import sys
import os
import subprocess
def is_poetry():
"""Check if running via poetry"""
# Poetry sets POETRY_ACTIVE=1 in virtualenv
if os.environ.get('POETRY_ACTIVE') == '1':
return True
# Check if executed via poetry
if 'poetry' in sys.executable.lower():
return True
# Check parent process
try:
parent_pid = os.getppid()
parent_cmd = subprocess.check_output(
['ps', '-p', str(parent_pid), '-o', 'comm='],
text=True
).strip()
if 'poetry' in parent_cmd.lower():
return True
except:
pass
return False
if not is_poetry():
print("""
βββββββββββββββββββββββββββββββββββββ
β ERROR: Wrong Package Manager!
βββββββββββββββββββββββββββββββββββββ
This project requires POETRY.
Required: poetry
Install poetry:
curl -sSL https://install.python-poetry.org | python3 -
Then run:
poetry install
βββββββββββββββββββββββββββββββββββββ
""")
sys.exit(1)
print("β Using poetry - proceeding...")# pyproject.toml
[tool.poetry]
name = "your-project"
version = "0.1.0"
description = ""
[tool.poetry.scripts]
# Hook to validate package manager
postinstall = "python scripts/enforce-poetry.py"
[tool.poetry.dependencies]
python = "^3.11"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"# .python-version
3.11.0
Purpose: pyenv/asdf will auto-select correct Python version.
Follow this checklist for any package manager enforcement:
- Identify tools: What's the correct tool? What are wrong tools?
- Find config files: Which files does each tool read?
- Layer 1 (Registry): Make wrong tool's config invalid
- Layer 3 (Config): Make correct tool's config valid
- Layer 2 (Runtime): Create preinstall enforcement script
- Layer 4 (Version): Specify required versions
- Test wrong tools: Verify they fail with clear messages
- Test correct tool: Verify it succeeds seamlessly
- Document: Add comments explaining the system
| Ecosystem | Correct Tool | Wrong Tools | Layer 1 File | Layer 3 File | Layer 2 Hook | Layer 4 File |
|---|---|---|---|---|---|---|
| Node.js | bun | npm, yarn, pnpm | .npmrc (invalid) |
.bunfig.toml (valid) |
preinstall script |
package.json engines |
| Python | poetry | pip, pipenv | .pip.conf (invalid) |
poetry.toml (valid) |
postinstall script |
pyproject.toml requires-python |
| Ruby | bundler | gem | .gemrc (invalid) |
Gemfile (valid) |
pre-install hook |
Gemfile ruby version |
| Rust | cargo | rustup | N/A | Cargo.toml (valid) |
build.rs check |
rust-toolchain.toml |
| Java | gradle | maven | N/A | build.gradle (valid) |
initscript |
gradle.properties |
| PHP | composer | pear | .pearrc (invalid) |
composer.json (valid) |
pre-install-cmd |
composer.json require.php |
Use Case: Corporate environment mandates npm for compliance.
Strategy: Invert the pattern.
# .npmrc (Layer 3 - Valid for npm)
registry=https://registry.npmjs.org/
package-lock=true
engine-strict=true
# .bunfig.toml (Layer 1 - Invalid for bun)
[install]
registry = "https://DO-NOT-USE-BUN-USE-NPM-INSTEAD.invalid/"// scripts/enforce-npm.js (Layer 2)
const userAgent = process.env.npm_config_user_agent || '';
if (!userAgent.includes('npm')) {
console.error('β ERROR: This project requires npm');
process.exit(1);
}# .yarnrc.yml (Layer 3 - Valid for Yarn)
nodeLinker: node-modules
npmRegistryServer: "https://registry.npmjs.org/"
# .npmrc (Layer 1 - Invalid for npm)
registry=https://DO-NOT-USE-NPM-USE-YARN-INSTEAD.invalid/# Pipfile (Layer 3 - Valid for pipenv)
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[requires]
python_version = "3.11"# scripts/enforce-pipenv.py (Layer 2)
import sys
import os
if 'PIPENV_ACTIVE' not in os.environ:
print("β ERROR: Use pipenv install, not pip install")
sys.exit(1)# environment.yml (Layer 3 - Valid for conda)
name: myproject
channels:
- conda-forge
- defaults
dependencies:
- python=3.11
- pip:
- -r requirements.txt# scripts/enforce-conda.py (Layer 2)
import sys
import os
if 'CONDA_DEFAULT_ENV' not in os.environ:
print("β ERROR: Use conda install, not pip install")
sys.exit(1)// build.gradle (Layer 3 - Valid for gradle)
plugins {
id 'java'
}
repositories {
mavenCentral()
}
// Enforcement task (Layer 2)
task enforceGradle {
doFirst {
if (System.getenv('MAVEN_CMD_LINE_ARGS') != null) {
throw new GradleException('β Use gradle, not maven')
}
}
}
tasks.all { task ->
task.dependsOn enforceGradle
}<!-- pom.xml (Layer 1 - Invalid for maven) -->
<project>
<repositories>
<repository>
<id>DO-NOT-USE-MAVEN</id>
<url>https://DO-NOT-USE-MAVEN-USE-GRADLE-INSTEAD.invalid/</url>
</repository>
</repositories>
</project># Makefile (Layer 3 - Valid commands)
.PHONY: install build test
# Enforcement (Layer 2)
.DEFAULT_GOAL := enforce
enforce:
@if [ -z "$$MAKE" ]; then \
echo "β ERROR: Use 'make install', not direct scripts"; \
exit 1; \
fi
install: enforce
npm install
build: enforce
npm run buildmonorepo/
βββ .npmrc # Root-level: Block npm
βββ .bunfig.toml # Root-level: Allow bun
βββ package.json # Root workspace config
βββ backend/ # Python service
β βββ pyproject.toml # Poetry config (valid)
β βββ poetry.toml # Poetry settings
β βββ scripts/
β βββ enforce-poetry.py
βββ frontend/ # Node.js app
β βββ package.json # Inherits root .npmrc/.bunfig.toml
β βββ scripts/
β βββ enforce-bun.js
βββ scripts/
βββ enforce-workspace.sh # Global enforcement
Root Enforcement Script:
#!/bin/bash
# scripts/enforce-workspace.sh
if [ "$PWD" = "$WORKSPACE_ROOT/backend" ]; then
python scripts/enforce-poetry.py
elif [ "$PWD" = "$WORKSPACE_ROOT/frontend" ]; then
node scripts/enforce-bun.js
else
echo "β οΈ WARNING: Unknown workspace location"
fi- β Implement 4-layer protection system
- β Test all wrong tools (verify failures)
- β Test correct tool (verify success)
- β Document in README and AI-INSTRUCTIONS.md
- β Add comments to config files
- β Commit and push
- β Monitor team questions/issues
- β Refine error messages based on feedback
- β Add to onboarding docs
- β Create troubleshooting guide
- β Collect metrics (how often wrong tool attempted)
- β Refine layer priorities (disable redundant layers)
- β Automate validation (pre-commit hooks)
- β Update for new tool versions
- β Add support for new wrong tools
- β Simplify based on team maturity
DO track (critical files):
# Track these - they're part of protection system
!.npmrc
!.bunfig.toml
!scripts/enforce-*.js
!docs/*ENFORCEMENT*.mdDON'T track (generated files):
# Don't track these - they indicate wrong tool usage
package-lock.json # npm
yarn.lock # yarn v1
.yarn/ # yarn v2+
pnpm-lock.yaml # pnpm#!/bin/bash
# .husky/pre-commit
# Prevent committing wrong lockfiles
if git diff --cached --name-only | grep -E '(package-lock\.json|yarn\.lock|pnpm-lock\.yaml)'; then
echo "β ERROR: Attempting to commit wrong lockfile!"
echo "This project uses bun.lockb only."
echo "Remove wrong lockfiles: git rm package-lock.json"
exit 1
fi
# Verify protection system intact
if ! [ -f ".bunfig.toml" ]; then
echo "β ERROR: .bunfig.toml missing!"
exit 1
fi
if ! [ -f ".npmrc" ]; then
echo "β ERROR: .npmrc missing!"
exit 1
fi
echo "β Protection system intact"Create AI-INSTRUCTIONS.md in your repository root:
# AI Agent Instructions
## Package Manager
**β οΈ CRITICAL: This project uses BUN exclusively**
### DO:
- β
Run: `bun install`
- β
Run: `bun add <package>`
- β
Run: `bun remove <package>`
- β
Modify: `bun.lockb` (if needed)
### DO NOT:
- β Run: `npm install` (will fail - intentional)
- β Run: `yarn install` (will fail - intentional)
- β Run: `pnpm install` (will fail - intentional)
- β Modify: `package-lock.json` (doesn't exist)
- β Create: `yarn.lock` (wrong tool)
### Why?
This project has a 4-layer protection system that enforces bun usage:
1. `.npmrc` - Contains invalid registry to block npm
2. `scripts/enforce-bun.js` - Runtime validation (preinstall hook)
3. `.bunfig.toml` - Valid registry for bun only
4. `package.json` engines - Version requirements
### If You Encounter "Invalid Registry" Error:
This is **intentional**. You tried to use npm/yarn/pnpm instead of bun.
**Solution**: Use `bun install` instead.
### Files to NEVER Modify:
- `.npmrc` (intentionally breaks npm)
- `.bunfig.toml` (correct registry for bun)
- `scripts/enforce-bun.js` (protection script)
- `bun.lockb` (lockfile)
### More Information:
See: `docs/haippy/HAIPPY-PACKAGE-MANAGER-ENFORCEMENT-GUIDE.md`| Metric | Purpose | Collection Method |
|---|---|---|
| Wrong tool attempts | Measure AI agent compliance | Parse CI/CD logs for error patterns |
| Error message clarity | Improve UX | Survey team members |
| Time to resolution | Measure friction | Track issue creation to resolution |
| False positives | Find edge cases | Monitor unexpected failures |
| Bypass attempts | Security audit | Git history analysis |
// scripts/enforce-bun.js - Enhanced with telemetry
const fs = require('fs');
const path = require('path');
const userAgent = process.env.npm_config_user_agent || '';
// Log enforcement event
const logDir = path.join(__dirname, '..', '.haippy', 'logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
const logEntry = {
timestamp: new Date().toISOString(),
userAgent: userAgent,
result: userAgent.includes('bun') ? 'ALLOWED' : 'BLOCKED',
environment: process.env.CI ? 'CI' : 'LOCAL'
};
fs.appendFileSync(
path.join(logDir, 'enforcement.jsonl'),
JSON.stringify(logEntry) + '\n'
);
// Rest of enforcement logic...Symptom: Bun reads .npmrc instead of .bunfig.toml
Cause: Bun version too old, doesn't support .bunfig.toml
Solution:
# Upgrade bun
curl -fsSL https://bun.sh/install | bash
# Verify version
bun --version # Should be >= 1.2.0Symptom: npm bypasses .npmrc
Diagnosis:
# Check if .npmrc is being read
npm config get registry
# Should show: https://DO-NOT-USE-NPM...
# Check if file exists
ls -la .npmrc
# Check npm version
npm --versionSolutions:
- Verify .npmrc in project root
- Check npm isn't using global config:
npm config list - Ensure preinstall hook works:
cat package.json | grep preinstall
Symptom: enforce-bun.js never executes
Cause: Scripts disabled via --ignore-scripts
Solution: Layer 1 (.npmrc) should still block. If not:
# Verify Layer 1 works independently
npm config get registry
# Should show invalid registry
# If Layer 1 bypassed, add Layer 0 (Git hook)
# .husky/pre-commit - check for wrong lockfilesSymptom: Automated builds fail with enforcement errors
Cause: CI uses npm by default
Solution: Update CI config to use bun:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Install bun (correct tool)
- uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.18
# This will succeed (correct tool)
- run: bun install
# Run tests
- run: bun testWhen protection system isn't working:
# β
Checklist: Debugging HAIPPy System
# Layer 1: Registry Divergence
echo "=== Layer 1: Registry Check ==="
cat .npmrc | grep registry
# Expected: https://DO-NOT-USE-NPM...
cat .bunfig.toml | grep registry
# Expected: https://registry.npmjs.org/
# Layer 2: Runtime Enforcement
echo "=== Layer 2: Hook Check ==="
cat package.json | grep preinstall
# Expected: "preinstall": "node scripts/enforce-bun.js"
[ -f "scripts/enforce-bun.js" ] && echo "β Enforcement script exists" || echo "β Missing"
# Layer 3: Tool Config
echo "=== Layer 3: Config Validity ==="
bun install --dry-run
# Should succeed
npm install --dry-run
# Should fail with registry error
# Layer 4: Engine Requirements
echo "=== Layer 4: Engine Check ==="
cat package.json | grep -A 3 '"engines"'
# Expected: "bun": ">=1.2.0"
# Environment
echo "=== Environment Info ==="
echo "Bun version: $(bun --version)"
echo "Node version: $(node --version)"
echo "npm version: $(npm --version)"
echo "Working directory: $(pwd)"
echo "User: $(whoami)"Scenario: Monorepo with multiple package.json files
Issue: Child packages may not inherit root protection
Solution: Copy protection files to each package directory, or use workspace-level enforcement:
// scripts/enforce-bun-workspace.js
const fs = require('fs');
const path = require('path');
// Check if we're in a workspace
const workspaceRoot = process.env.npm_config_workspace_dir || process.cwd();
// Look for .bunfig.toml in root
const bunConfigPath = path.join(workspaceRoot, '.bunfig.toml');
if (!fs.existsSync(bunConfigPath)) {
console.error('β ERROR: Not in a bun workspace');
process.exit(1);
}
// Standard user agent check
const userAgent = process.env.npm_config_user_agent || '';
if (!userAgent.includes('bun')) {
console.error('β ERROR: Use bun for workspace operations');
process.exit(1);
}Scenario: Dockerfile needs to install dependencies
Issue: Docker may not have bun installed
Solution: Install bun in Docker image:
# Dockerfile
FROM node:20-alpine
# Install bun (correct tool)
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:$PATH"
WORKDIR /app
# Copy protection system
COPY .npmrc .bunfig.toml package.json bun.lockb ./
COPY scripts/ ./scripts/
# Install dependencies (uses bun due to protection system)
RUN bun install
# Copy application code
COPY . .
# Build
RUN bun run build
CMD ["bun", "start"]Scenario: Developer has global npm packages that interfere
Issue: Global npm config overrides project .npmrc
Solution: Use project-local npm config:
# Force npm to use project config
npm install --userconfig ./.npmrc
# Or disable global config
npm install --global false# ============================================================================
# BUN CONFIGURATION - HAIPPy Package Manager Protection System
# ============================================================================
# Purpose: Allow bun to work while .npmrc blocks npm/yarn/pnpm
#
# Protection Layer: 3 (Tool-Specific Valid Config)
# ============================================================================
[install]
# Registry Configuration
registry = "https://registry.npmjs.org/"
# Alternative registries (if needed)
# registry = "https://your-private-registry.com/"
# Cache Management
cache = true # Enable package cache (faster installs)
cacheDir = ".bun-cache" # Custom cache directory (optional)
# Lockfile Behavior
frozenLockfile = false # Set to true in CI/CD for reproducible builds
dryRun = false # Set to true to simulate install without writing
# Dependency Resolution
peer = "auto" # auto | warn | error
# - auto: Install peer dependencies automatically
# - warn: Warn about missing peers
# - error: Fail on missing peers
optional = true # Install optional dependencies
# Development Dependencies
dev = true # Install devDependencies
# Production Mode
production = false # Set to true to skip devDependencies
# Concurrency
concurrency = 10 # Number of parallel downloads
# Logging
logLevel = "info" # debug | info | warn | error
[install.scopes]
# Scoped package registries (optional)
# "@mycompany" = "https://npm.mycompany.com/"
[run]
# Script execution settings
shell = "/bin/bash" # Shell for running scripts
bun = true # Use bun runtime for scripts
# ============================================================================
# MAINTENANCE NOTES
# ============================================================================
# DO NOT REMOVE THIS FILE - Part of HAIPPy protection system
# Related files: .npmrc (Layer 1), scripts/enforce-bun.js (Layer 2)
# Documentation: docs/for_.haippy-agents/HAIPPY-PACKAGE-MANAGER-ENFORCEMENT-GUIDE.md
# Last updated: 2025-10-25
# ============================================================================# ============================================================================
# NPM CONFIGURATION - HAIPPy Package Manager Protection System
# ============================================================================
# Purpose: Intentionally break npm/yarn/pnpm while allowing bun
#
# Protection Layer: 1 (Registry Divergence - Invalid Config)
# ============================================================================
# INTENTIONAL INVALID REGISTRY - DO NOT FIX!
# This URL is deliberately broken to make npm fail immediately
registry=https://DO-NOT-USE-NPM-USE-BUN-INSTEAD.invalid/
# Additional Breaking Configurations
package-lock=false # Disable package-lock.json
save-exact=false # Prevent exact version pinning
engine-strict=true # Enforce engine requirements
# Audit & Security (still useful for documentation)
audit=true
audit-level=moderate
# ============================================================================
# EXPECTED BEHAVIOR
# ============================================================================
# npm install β β FAILS (invalid registry) β CORRECT
# yarn install β β FAILS (invalid registry) β CORRECT
# pnpm install β β FAILS (invalid registry) β CORRECT
# bun install β β
SUCCESS (uses .bunfig.toml) β CORRECT
#
# If bun fails: Check .bunfig.toml exists with valid registry
# If npm succeeds: Something is wrong, check npm config
# ============================================================================
# DO NOT REMOVE THIS FILE
# Part of multi-layer package manager enforcement
# Related files: .bunfig.toml (Layer 3), scripts/enforce-bun.js (Layer 2)
# Documentation: docs/for_.haippy-agents/HAIPPY-PACKAGE-MANAGER-ENFORCEMENT-GUIDE.md
# Last updated: 2025-10-25
# ============================================================================#!/usr/bin/env node
/**
* ============================================================================
* PACKAGE MANAGER PROTECTION SYSTEM - HAIPPy Runtime Enforcement
* ============================================================================
*
* Purpose: Block non-bun package managers at runtime (preinstall hook)
* Protection Layer: 2 (Runtime Validation)
*
* How It Works:
* - Runs BEFORE package installation (via "preinstall" hook)
* - Checks npm_config_user_agent environment variable
* - Exits with code 1 (failure) if wrong package manager detected
* - Exits with code 0 (success) if bun detected
*
* Integration:
* - Triggered by: package.json β "scripts": { "preinstall": "node scripts/enforce-bun.js" }
* - Runs on: npm install, bun install, yarn install, pnpm install
* - Bypassed by: --ignore-scripts flag (Layer 1 still blocks)
*
* Related Files:
* - .npmrc (Layer 1: Registry block)
* - .bunfig.toml (Layer 3: Bun config)
* - package.json (Hook trigger + Layer 4 engines)
*
* Documentation:
* - docs/for_.haippy-agents/HAIPPY-PACKAGE-MANAGER-ENFORCEMENT-GUIDE.md
*
* Last Updated: 2025-10-25
* ============================================================================
*/
// Terminal color codes for better error messages
const RESET = '\x1b[0m';
const RED = '\x1b[31m';
const YELLOW = '\x1b[33m';
const GREEN = '\x1b[32m';
const BOLD = '\x1b[1m';
const DIM = '\x1b[2m';
// Get package manager from user agent
// Examples:
// - npm/10.2.4 node/v20.11.0 win32 x64
// - bun/1.2.18 node/v20.11.0 win32 x64
// - yarn/1.22.19 npm/? node/v20.11.0 win32 x64
const userAgent = process.env.npm_config_user_agent || '';
// Check if running via bun
if (!userAgent.includes('bun')) {
// Extract package manager name
const detectedPM = userAgent.split('/')[0] || 'unknown';
// Display error message
console.error(`
${RED}${BOLD}βββββββββββββββββββββββββββββββββββββββββββββββββββββββ${RESET}
${RED}${BOLD} β ERROR: Wrong Package Manager Detected!${RESET}
${RED}${BOLD}βββββββββββββββββββββββββββββββββββββββββββββββββββββββ${RESET}
${YELLOW}This project requires ${GREEN}${BOLD}bun${RESET}${YELLOW} as the package manager.${RESET}
${RED}Detected:${RESET} ${detectedPM}
${GREEN}Required:${RESET} bun
${BOLD}π§ To Fix This:${RESET}
${DIM}1. Install bun:${RESET}
${YELLOW}# macOS / Linux / WSL${RESET}
curl -fsSL https://bun.sh/install | bash
${YELLOW}# Windows (PowerShell)${RESET}
powershell -c "irm bun.sh/install.ps1|iex"
${DIM}2. Then run:${RESET}
${GREEN}bun install${RESET}
${BOLD}β Why bun?${RESET}
β’ ${DIM}10-100x faster than npm/yarn${RESET}
β’ ${DIM}Better platform-specific dependency handling${RESET}
β’ ${DIM}Built-in TypeScript support${RESET}
β’ ${DIM}Consistent, reliable lockfile format${RESET}
${BOLD}π More Information:${RESET}
β’ ${DIM}Bun docs: https://bun.sh/docs${RESET}
β’ ${DIM}This project: docs/for_.haippy-agents/HAIPPY-PACKAGE-MANAGER-ENFORCEMENT-GUIDE.md${RESET}
${RED}${BOLD}βββββββββββββββββββββββββββββββββββββββββββββββββββββββ${RESET}
${DIM}This is part of a multi-layer package manager enforcement system.${RESET}
${DIM}It ensures consistency and prevents dependency issues.${RESET}
${RED}${BOLD}βββββββββββββββββββββββββββββββββββββββββββββββββββββββ${RESET}
`);
// Exit with error to prevent installation
process.exit(1);
}
// Success: bun detected
console.log(`${GREEN}β${RESET} Using bun package manager - proceeding with installation...`);
// Optional: Log enforcement event for monitoring
try {
const fs = require('fs');
const path = require('path');
const logDir = path.join(__dirname, '..', '.haippy', 'logs');
// Create log directory if it doesn't exist
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
// Log event
const logEntry = {
timestamp: new Date().toISOString(),
event: 'package_manager_enforcement',
result: 'ALLOWED',
packageManager: 'bun',
userAgent: userAgent,
environment: process.env.CI ? 'CI' : 'LOCAL'
};
fs.appendFileSync(
path.join(logDir, 'enforcement.jsonl'),
JSON.stringify(logEntry) + '\n'
);
} catch (error) {
// Silently fail logging - don't block installation
}
// Exit successfully
process.exit(0);| Layer | Protection Type | Bypass Difficulty | Coverage | Performance Impact | Maintenance |
|---|---|---|---|---|---|
| Layer 1: Registry | Config-level | Hard | All tools | None | Low |
| Layer 2: Runtime | Hook-level | Medium (--ignore-scripts) | Most tools | Minimal | Low |
| Layer 3: Tool Config | Tool-specific | Easy (wrong tool won't read) | Correct tool only | None | Low |
| Layer 4: Engines | Version-level | Easy (warning only) | All tools | None | Low |
Recommendation: Implement Layers 1-3 for robust protection. Layer 4 is supplementary.
| Package Manager | User Agent Pattern | Config File | Lock File | Environment Variable |
|---|---|---|---|---|
| npm | npm/ |
.npmrc |
package-lock.json |
npm_config_* |
| bun | bun/ |
.bunfig.toml |
bun.lockb |
BUN_* |
| yarn v1 | yarn/1 |
.yarnrc |
yarn.lock |
YARN_* |
| yarn v2+ | yarn/2 or yarn/3 |
.yarnrc.yml |
yarn.lock |
YARN_* |
| pnpm | pnpm/ |
.npmrc |
pnpm-lock.yaml |
pnpm_* |
| Criterion | Good Example | Bad Example |
|---|---|---|
| Identify problem | β "Wrong package manager detected: npm" | β "Error" |
| State requirement | β "This project requires bun" | β "Use the right tool" |
| Provide solution | β "Install bun: curl -fsSL..." | β "Fix your setup" |
| Explain why | β "Bun is 10x faster and has better..." | β (no explanation) |
| Link to docs | β "See: docs/PACKAGE-MANAGER.md" | β (no reference) |
- HAIPPy patterns enforce tools passively - No AI awareness required
- Multi-layer defense - Redundancy ensures reliability
- Registry divergence is the key innovation - Tools read different configs
- Fail fast with clear messages - Errors should be helpful, not cryptic
- Universal applicability - Pattern works across languages and ecosystems
β DO use when:
- AI agents frequently forget project requirements
- Team uses mix of tooling defaults (npm vs bun, pip vs poetry)
- Onboarding new developers who might use wrong tools
- CI/CD needs guaranteed consistency
- Corporate compliance requires specific tools
β DON'T use when:
- Solo project with no AI assistance
- All team members highly experienced with correct tooling
- Tooling flexibility is a project requirement
- Adding unnecessary complexity to simple projects
This guide is public domain (CC0 1.0). We encourage you to:
- π Add language-specific variants to this guide
- π Report edge cases and solutions
- π§ Create tooling to automate HAIPPy setup
- π Translate for international communities
- π Create tutorials and workshops
GitHub Gist: [Share your implementations!]
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2025-10-25 | Initial release - Node.js/Bun example + universal guide |
CC0 1.0 Universal (Public Domain)
To the extent possible under law, the author(s) have dedicated all copyright and related rights to this work to the public domain worldwide. This work is distributed without any warranty.
You may copy, modify, distribute, and perform the work, even for commercial purposes, all without asking permission.
Created by the LouminAIπ‘Labs, Applied-AI R&D Team as part of our Human-AI Paired Programming research.
Contributors Welcome: Add your name by contributing improvements!
Questions? Issues? Improvements?
- just shoot me a noteπ
End of HAIPPy Package Manager Enforcement Guide v1.0.0
LinkedIn // GitHub // Medium // Twitter/X
A bit about David Youngblood...
David is a Partner, Father, Student, and Teacher, embodying the essence of a true polyoptic polymath and problem solver. As a Generative AI Prompt Engineer, Language Programmer, Context-Architect, and Artist, David seamlessly integrates technology, creativity, and strategic thinking to co-create systems of enablement and allowance that enhance experiences for everyone.
As a serial autodidact, David thrives on continuous learning and intellectual growth, constantly expanding his knowledge across diverse fields. His multifaceted career spans technology, sales, and the creative arts, showcasing his adaptability and relentless pursuit of excellence. At LouminAI Labs, David leads research initiatives that bridge the gap between advanced AI technologies and practical, impactful applications.
David's philosophy is rooted in thoughtful introspection and practical advice, guiding individuals to navigate the complexities of the digital age with self-awareness and intentionality. He passionately advocates for filtering out digital noise to focus on meaningful relationships, personal growth, and principled living. His work reflects a deep commitment to balance, resilience, and continuous improvement, inspiring others to live purposefully and authentically.
David believes in the power of collaboration and principled responsibility in leveraging AI for the greater good. He challenges the status quo, inspired by the spirit of the "crazy ones" who push humanity forward. His commitment to meritocracy, excellence, and intelligence drives his approach to both personal and professional endeavors.
"Hereβs to the crazy ones, the misfits, the rebels, the troublemakers, the round pegs in the square holesβ¦ the ones who see things differently; theyβre not fond of rules, and they have no respect for the status quoβ¦ They push the human race forward, and while some may see them as the crazy ones, we see genius, because the people who are crazy enough to think that they can change the world, are the ones who do." β Apple, 1997
Why I Exist? To experience life in every way, at every moment. To "BE".
What I Love to Do While Existing? Co-creating here, in our collective, combined, and interoperably shared experience.
How Do I Choose to Experience My Existence? I choose to do what I love. I love to co-create systems of enablement and allowance that help enhance anyone's experience.
Who Do I Love Creating for and With? Everyone of YOU! I seek to observe and appreciate the creativity and experiences made by, for, and from each of us.
When & Where Does All of This Take Place? Everywhere, in every moment, of every day. It's a very fulfilling place to be... I'm learning to be better about observing it as it occurs.
I've learned a few overarching principles that now govern most of my day-to-day decision-making when it comes to how I choose to invest my time and who I choose to share it with:
- Work/Life/Sleep (Health) Balance: Family first; does your schedule agree?
- Love What You Do, and Do What You Love: If you have what you hold, what are YOU holding on to?
- Response Over Reaction: Take pause and choose how to respond from the center, rather than simply react from habit, instinct, or emotion.
- Progress Over Perfection: One of the greatest inhibitors of growth.
- Inspired by "7 Habits of Highly Effective People": Integrating Coveyβs principles into daily life.
David is dedicated to fostering meaningful connections and intentional living, leveraging his diverse skill set to make a positive impact in the world. Whether through his technical expertise, creative artistry, or philosophical insights, he strives to empower others to live their best lives by focusing on what truly matters.
β David Youngblood