Skip to content

Latest commit

 

History

History
187 lines (144 loc) · 13.3 KB

File metadata and controls

187 lines (144 loc) · 13.3 KB

Shipwright — Agent Instructions

⚠️ TOKEN DISCIPLINE. Check file size first. Grep over Read. Use offset/limit. Smallest diff that solves the problem. Delete dead code, unused imports, stale comments. Call out irrelevant context before proceeding. Bloat degrades reasoning. ⚠️

Read this file in full. Rules below are NON-NEGOTIABLE — violations are rejected in review.

Project Overview

Shipwright is a portfolio-shared library that scaffolds binary and IDE-extension deployment in a consistent way across multiple downstream products (Too Many Cooks, Deslop, Basilisk, SharpLsp, dart_mutant — see docs/specs/source-projects.md). It defines the binary version contract, manifest schema, compatibility matrix, and the host-side resolution algorithm that IDE extensions use to locate and verify their backing binaries before launching them. See docs/specs/ for the authoritative behavior specs and docs/plans/ for the implementation plan.

Primary language(s): Rust (workspace, libraries), TypeScript/Node (SDKs, MCP, VS Code helpers, fixture tests), Dart, C#/.NET, Kotlin/Gradle, and Eleventy for the docs website. Build command: make ci Test command: make test Lint command: make lint

Too Many Cooks (Multi-Agent Coordination)

If the TMC server is available: register on start (name, intent, files), lock files before editing, broadcast your plan, check messages periodically, release locks when done. Never edit a locked file — wait or take another approach.

Hard Rules — Universal (no exceptions)

  • NO git write commands. No add, commit, push, checkout, merge, rebase, branch creation, tag movement, or worktrees. Read-only status/diff/log commands are allowed for orientation. CI handles source-control writes unless a dedicated PR-submission skill explicitly says otherwise.
  • NEVER push to main directly. Every change goes through PR -> CI green -> merge.
  • NEVER list an agent as a commit co-author. No AI/agent Co-Authored-By trailers.
  • Work on exactly one branch at a time. Reuse the existing feature branch; if multiple feature branches exist, stop and converge them before doing feature work.
  • Auto-memory is off. Persistent rules must be changed in this file through review, not silently captured by an agent memory feature.
  • ZERO DUPLICATION. Search before writing. Move code, don't copy it.
  • NO EXCEPTIONS for control flow. Return Result<T,E>. Exceptions are panic-level only.
  • NO REGEX on structured data. Use real parsers for JSON/YAML/TOML/code.
  • NO PLACEHOLDERS. Use todo!() — never silently no-op.
  • Functions < 20 lines. Files < 500 lines. Refactor when over.
  • Never delete or skip tests. Never remove assertions. 100% coverage is the goal.
  • make test is FAIL-FAST. Stops at first failing test. Never --no-fail-fast. Saves CI minutes; stops agents idling on doomed runs. See REPO-STANDARDS-SPEC [TEST-RULES].
  • make test ALWAYS computes coverage AND enforces it. Threshold lives in coverage-thresholds.json at the repo root — NOT env vars, NOT gh repo variables, NOT CI YAML. Below threshold = pipeline fails. Ratchet only. See [COVERAGE-THRESHOLDS-JSON].
  • Prefer E2E/integration tests. Unit tests only for isolating problems.
  • Heavy structured logging everywhere. See Logging below.
  • No linter suppressions. Fix the code.
  • Pure functions over statements.
  • Spec IDs are hierarchical, non-numeric: [GROUP-TOPIC] / [GROUP-TOPIC-DETAIL] or SWR-GROUP-TOPIC / SWR-GROUP-TOPIC-DETAIL (e.g., [AUTH-TOKEN-VERIFY], [CI-TIMEOUT], SWR-IDE-DOTNET-RUNTIME). Same-group sections sit adjacent in the TOC. NO sequential numbers ([SPEC-001], SWR-SPEC-001). Code/tests/docs that implement a spec section MUST reference its ID in a comment so grep SWR-IDE finds spec → code → tests in one shot.

Logging Standards

  • Structured logging library only. Never println! (Rust), console.log (TS), print (Dart), or Debug.WriteLine (C#) for diagnostics. Libraries: Rust tracing, TS pino, Dart dart_logging, C# Microsoft.Extensions.Logging + Serilog.
  • Log at entry/exit of significant operations. Levels: error|warn|info|debug|trace. Silent failures are forbidden.
  • Structured fields, not string interpolation. { binary: "deslop-lsp", expected: "0.3.1", found: "0.2.0" } — never "deslop-lsp version mismatch".
  • NEVER log PII. NEVER log secrets. Log "key: present" or a truncated hash, never the value.

Hard Rules — Language-Specific

Rust

  • No unwrap()/expect() in production (tests OK for expect).
  • No panic!/todo!/unimplemented!/unreachable! in production.
  • No unsafe {} or allow(clippy::...) without documented justification.
  • All public items have /// doc comments.
  • thiserror for library errors; anyhow only in application code.
  • Workspace lints in Cargo.toml [workspace.lints] are deny-by-default — do not weaken them.
  • crates/shipwright-host is the pure binary-resolution algorithm with NO I/O. The probe is injected. Keep it that way.

TypeScript / Node

  • No any (use unknown and narrow). No ! non-null assertion. No // @ts-ignore/@ts-nocheck.
  • No implicit any — annotate every parameter and return type.
  • No as Type casts without a comment explaining safety.
  • No throwing — return Result<T,E> (discriminated union).
  • Tests use the Node built-in node --test runner (see tests/fixtures.test.mjs and tools/validate-manifest/). New TS code is allowed but must run on Node ≥ 20 with "type": "module".

Dart

  • Public library APIs live under clients/dart/shipwright/lib/ and must stay null-safe.
  • Run dart analyze and dart test --fail-fast from clients/dart/shipwright before touching Dart resolver behavior.
  • Source-controlled package versions stay at 0.0.0-dev; release tags stamp real versions.

C# / .NET

  • Keep nullable reference types enabled and warnings treated as errors.
  • Tests use xUnit and must run fail-fast through dotnet test -- xunit.stopOnFail=true.
  • Source-controlled <Version> values stay at 0.0.0-dev; release tags stamp real versions.

Kotlin / Gradle

  • Kotlin client code lives in clients/kotlin/shipwright-intellij/.
  • Use the checked-in Gradle wrapper; do not assume a system Gradle installation.

Testing Rules

  • Never delete a failing test. Fix the code or the expectation.
  • Never skip a test without a ticket number AND expiry date in the skip reason.
  • Specific assertions only. assert.ok(true) is illegal.
  • No try/catch in tests that swallows exceptions and asserts success.
  • Deterministic. No sleep(), no timing dependencies, no random state.
  • E2E tests: black-box only — public APIs or CLI. Never reach into internals.
  • Manifest fixtures live in fixtures/manifests/ and fixtures/golden-manifests/. Add a fixture for every new schema branch you cover.

Build Commands

Agent PMO make targets

make build   # compile everything (Rust workspace + Node tools)
make test    # FAIL-FAST tests + coverage + threshold (ONLY test entry point)
make lint    # all linters/analyzers (no formatting)
make fmt     # format in place
make clean   # remove build artifacts
make ci      # lint + test + build (full CI simulation)
make setup   # post-create dev environment setup

make test runs the test runner with its fail-fast flag, collects coverage, asserts measured ≥ threshold from coverage-thresholds.json, and exits non-zero on any failure. To debug a single test, invoke the runner directly — that is not a Makefile target.

make fmt formats code in-place. make lint runs linters/analyzers (read-only, no formatting). make test runs tests with coverage. Three separate targets — no overlap.

Deslop Duplication Gate

Shipwright contains Deslop-supported languages (Rust, C#, Dart), so agents MUST use the Deslop loop when changing code:

  • Before authoring any function, method, class, helper, fixture, or test setup, call find-similar. Reuse existing code for identical/nearly-identical matches or signals.fused >= 0.85.
  • After changing code, run rescan and check top-offenders; inspect any cluster you plan to touch with cluster-by-id.
  • Never silence duplication by raising .deslop.toml, hiding code, or making trivial shape changes.

Placeholder Versions — NON-NEGOTIABLE

All version fields in source (Cargo.toml, package.json, *.csproj, pubspec.yaml, shipwright.json) MUST be 0.0.0-dev. Real versions are stamped at release time by shipwright-version-stamp from the git tag — never hard-coded in source. Hard-coded release versions in source are a release-engineering defect. See [SWR-VERSION-BUILD-STAMPING] in docs/specs/binary-version-contract.md.

Repo Structure

crates/                            # Rust workspace members
  shipwright-host/                 # pure binary-resolution algorithm (no I/O)
  shipwright-manifest/             # manifest schema and version-format helpers
  shipwright-zed/                  # Zed extension helpers
clients/                           # per-language client SDKs (placeholders)
  dart/  dotnet/  kotlin/  ts/
extensions/
  shipwright-tools/                # VS Code extension and visual manifest editor
docs/
  specs/                           # behaviour specs (binary-version-contract, compatibility-matrix, etc.)
  plans/                           # implementation plans with TODO checklists
website/                           # Eleventy + eleventy-plugin-techdoc documentation site
schemas/                           # JSON schemas (shipwright, version-manifest, platforms, test-vectors)
fixtures/                          # manifests, golden manifests, version outputs, platform definitions
tools/
  validate-manifest/               # Node-based AJV validator (shipwright-validate-manifest)
  shipwright-version-stamp/         # release-time version stamper
templates/
  gh-actions/                      # downstream-project release/publish workflow templates
examples/ci/                       # example consumer CI configurations
tests/fixtures.test.mjs            # Node test runner over fixtures

Architecture invariants:

  1. The Rust host crate (shipwright-host) MUST stay pure — no filesystem, network, or process spawning. The version-probe function is injected by the caller (the IDE extension).
  2. The JSON schemas in schemas/ are the source of truth for the manifest format. Generated client code (Rust, TS, Dart, .NET, Kotlin) consumes these schemas.
  3. Every fixture in fixtures/ is exercised by tests/fixtures.test.mjs against the AJV validator in tools/validate-manifest/.
  4. templates/gh-actions/ is shipped as-is to downstream products — never inline-modify; treat as published interface.

VS Code Version Targeting — NON-NEGOTIABLE

All VS Code extension tests, builds, and CI pipelines MUST target the latest stable VS Code release. NEVER pin or downgrade to an older VS Code version to work around test infrastructure issues. Fix the infrastructure instead.

  • Extension E2E tests run against the latest VS Code via @vscode/test-electron (downloads latest automatically).
  • engines.vscode in package.json declares the minimum supported version, not the test version.
  • If @vscode/test-electron breaks on a new VS Code release, fix the launcher — do NOT pin a version.

.NET Runtime in VS Code Extensions — NON-NEGOTIABLE

Any VS Code extension with framework-dependent .NET sidecars ("language": "dotnet" components) MUST use the .NET Install Tool extension to acquire the runtime. This is the ONLY permitted approach.

  • "extensionDependencies": ["ms-dotnettools.vscode-dotnet-runtime"] in package.json
  • dotnet.findPath then dotnet.acquire commands on activation — non-interactive toast spinner
  • Set DOTNET_ROOT in the env passed to the Rust LSP host
  • On failure: non-modal error notification + retryDotnetAcquisition command
  • NEVER crash on missing .NET. NEVER dotnet tool install. NEVER hand-roll a download.

Full spec: docs/specs/ide-extension-deployment.md [SWR-IDE-DOTNET-RUNTIME]

Key External References

Agents working on VSIX bundling, CI templates, or the vscode host library MUST read these before writing any code. The Microsoft sample is the authoritative source — follow it exactly.