Part 4 of 4
opencode rules for Windows and development
We create two rule files that guide opencode: one for PowerShell/Windows and one for the portable development environment on J:, with UTF-8 encoding, modules, and a Git workflow adapted to solo work.
After parts 1-3 I had portable opencode running on the SSD with OmniRoute and OpenRouter. But the assistant didn’t know my environment: where Python lives, that I’m on PowerShell, what tooling each project uses. The solution was writing two rule files that opencode loads on startup and follows automatically.
1. Where rules live in opencode
In the portable install, config lives at J:\opencode\xdg\config\opencode\. Opencode automatically loads the .md files inside the rules folder:
New-Item -ItemType Directory -Path "J:\opencode\xdg\config\opencode\rules" -Force
I split behavior into two files with distinct responsibilities:
J:\opencode\xdg\config\opencode\rules\
├── windows_rules.md ← environment and terminal (PowerShell, paths, encoding)
└── development_rules.md ← dev ecosystems (Node, Python, Git, env vars)
Download the rules
Here’s the package with both files ready to copy into J:\opencode\xdg\config\opencode\rules\:
2. Windows rules: the baseline
The first file started with the essentials: I’m on native Windows with PowerShell and I should never use Unix commands. The Unix → PowerShell translation table was the core piece:
| ❌ BAD (Unix) | ✅ GOOD (PowerShell) |
|---|---|
ls -la or ll |
Get-ChildItem -Force |
touch archivo.txt |
New-Item -ItemType File -Name archivo.txt |
mkdir -p dir/subdir |
New-Item -ItemType Directory -Force -Path dir\subdir |
rm -rf carpeta |
Remove-Item -Recurse -Force carpeta |
grep "texto" archivo.txt |
Select-String -Pattern "texto" -Path archivo.txt |
comando1 && comando2 |
comando1 ; comando2 |
Chaining rule: in PowerShell 5.1
&&and||caused syntax errors; the semicolon was the only portable option. This changed with PowerShell 7 (we’ll see it in section 6).
I also locked in the efficiency rules: short answers, group commands in a single request, selective reading (never read a whole file over 300 lines), and don’t return entire files when only a few lines changed.
3. Expanding with PowerShell specifics
The baseline wasn’t enough. I added ten subsections with the PowerShell that’s actually useful day to day:
- 3.1 Paths: native
\and double quotes for spaces ("C:\Program Files\app") - 3.2 Environment variables:
$env:NAME(not$NAMEor%NAME%) - 3.3 Encoding: UTF-16 default; force UTF-8 (lesson in section 5)
- 3.4 Error handling:
$?,$LASTEXITCODE,try/catch,-ErrorAction Stop - 3.5 Pipeline: .NET objects,
Where-Object,Select-Object,ForEach-Object - 3.6 Aliases:
gci,ni,ri,cp,mv,cat,ps,kill - 3.7 Working directory:
Set-Location,Push-Location/Pop-Location - 3.8 Quotes: double quotes expand
$(...), single quotes are literal - 3.9 Comparison operators:
-eq,-like,-match,-contains,-inwith c/i suffixes - 3.10 Background:
Start-Process,Start-Job,Start-ThreadJob
4. Restructure for quick lookup
With 13 subsections, navigating by eye was slow. I restructured the file with a table of contents with anchors at the top:
## Table of contents
1. [General Principles](#1-general-principles)
2. [Basic Commands (Unix → PowerShell)](#2-basic-commands-unix--powershell)
3. [PowerShell Specifics](#3-powershell-specifics)
- 3.1 [Paths and Separators](#31-paths-and-separators)
- ...
Each section now has its number and anchor: the assistant locates “encoding” or “background jobs” at a glance without reading the whole file.
5. Add help and modules (the truly essential stuff)
Reviewing the file, two things were missing that I use daily even though they sound advanced:
- 3.11 Help system:
Get-Help comando -Full,-Examples,-Online,Update-Help - 3.12 Modules:
Get-Module -ListAvailable,Import-Module,Install-Module,Find-Module
Lesson: in PowerShell 5.1
-Encoding utf8creates a BOM
Set-ContentandOut-File -Encoding utf8write UTF-8 with BOM, and modern tooling (Vite, Astro, Svelte) fails on those files. The portable fix: use the .NET method[IO.File]::WriteAllText("archivo", "texto"), which writes UTF-8 without BOM by default. Another fix from the same review: when launching dev servers in the background, redirect output to a log (or$null) so the terminal doesn’t hang. With PowerShell 7 the BOM issue went away entirely (next section).
6. Migrating to PowerShell 7
I installed PowerShell 7 and the picture got better:
- Encoding 3.3: now
Set-Content/Out-File -Encoding utf8produce UTF-8 without BOM by default — the[IO.File]::WriteAllTextworkaround is no longer needed - Chaining:
&&and||work natively in PS7+;;stays as the maximum-compatibility option - 3.13 What’s new: pipeline chain operators, ternary
cond ? a : b, null coalescing??,$PSVersionTable.PSEdition = "Core", cross-platform, better performance (.NET 6+)
I updated section 2 and 3.3 to reflect the new environment, keeping a 5.1 note for compatibility in case we ever touch an older machine.
7. Development rules: the dev environment
The second file attacks the same problem but for code: what tooling to expect in each technology and how to work without cluttering the terminal.
Node.js and frontend:
- Silent installs, always:
npm install paquete --no-fund --no-audit --loglevel=error - Binaries with
npx(never-gunless asked):npx astro add tailwind,npx svelte-check - Dev servers (
npm run dev) block the terminal → background technique fromwindows_rules.mdor warn the user
Quality and testing (2.4 and 2.5): detect what the project uses (lint, format, typecheck), run them after touching code, and when a test fails, fix the real code — never tweak a test just to make it pass.
Python (portable J: environment): always call the executable directly, no venv activation:
| Context | Command/Path |
|---|---|
| Global | J:\Python\python.exe script.py |
| Local venv | .\venv\Scripts\python.exe script.py |
| Install (quiet) | .\venv\Scripts\python.exe -m pip install -q paquete |
Plus environment setup, requirements.txt, pyproject.toml + pip-tools, and pip freeze > requirements.txt.
Environment variables: local untracked .env, versioned .env.example with dummy keys, loading with dotenv or node --env-file=.env (Node 20.6+), and never hardcode secrets.
8. Git adapted to a solo developer
The first version applied a team workflow (protected branch, mandatory PRs, squash). For my solo work it was too restrictive. I adapted it:
- 4.1 Agile flow / solo dev: direct commits and pushes to
mainfor fast iterations; separate branches only for big features that could break the app; integration withgit merge(ideally--ff-onlyor with a prior rebase) for a linear history - 4.2 Hooks: if the
pre-commit(lint + format + typecheck) orcommit-msgfails, never use--no-verify— read the error, fix it, and retry the commit cleanly
Issues and lessons
Lesson: rules evolve with the environment
The UTF-8 BOM was only an issue in PowerShell 5.1. After migrating to PS7, the rule (and its recommended workaround) stopped making sense. Rule files aren’t static: they’re reviewed every time the tool changes, not the other way around.
Lesson: separate responsibilities between rule files
windows_rules.mdtalks about how things run (PowerShell, paths, encoding);development_rules.mdabout what runs (npm, Python, Git). Keeping them separate keeps each file flat, short, and single-purpose.
Lesson: what seems “advanced” is often daily
Get-HelpandImport-Modulelooked like advanced-manual material, but they’re two of the commands I use practically every day. We prioritized rules by usage frequency, not by complexity level.
Closing
With these two files, opencode knows what environment it lives in and how to work efficiently: correct PowerShell commands, reliable UTF-8 encoding, project tooling detected before running anything, and a Git workflow designed for solo development. And as a good SSD citizen: everything lives in J:\opencode\xdg\config\opencode\rules\, ready to move between PCs without dragging host configuration along.
The series lives on: the assistant now knows the operating system and the development ecosystem. In the next part, any specific adjustments that come up along the way will be documented the same way.