Skip to content

FABRICA / CODE RULES

The package manager
for your engineering rules

Version your best practices. Share them across projects. Use them to show your agents how to write and validate good code.

Your coding agent acme-checkoutEXAMPLE SESSION

You: Add logging for successful sign-ins.

First, I’ll read your logging rule.

Read file:.code-rules/rules/practices/logging/no_secrets_in_logs.mddone
Never write secrets to logs.

I’m writing the logging code to follow your rule: include user IDs, never passwords.

Edit:sign-in.tsdone
log.info({ userId }, "Signed in");

Verified: no passwords in the logs.

Run:bun testdone
✓ Sign-ins logged · passwords excluded
01 / CODIFY

Define the practices your agents should follow.

Write rules in Markdown to tell agents how to write and validate code. Cover technologies like Go or React, and practices like testing, error handling, or logging.

Learn how to write rules →
EXAMPLE RULE · ABBREVIATED
practices/error-handling/make-errors-actionable.md
---
title: Make error messages actionable
whenToRead: When writing or reviewing validation errors shown to users.
---

Error messages must explain what went wrong and how to fix it.

**Incorrect:** "Upload failed."

**Correct:** "File too large. Choose a file up to 10 MB."

### Validation

Upload an oversized file and check that the error
states the size limit and how to proceed.
02 / SHARE

Declare rules for a single repo, or an entire organization.

Each project keeps its configuration and rules in the Code Rules directory, .code-rules/. Publish shared defaults from an organization .code-rules repository and import them. Combine shared and project-specific rules so agents have the right guidance in each repo.

See how rule libraries work →
EXAMPLE RULE LIBRARY
acme/.code-rules/
rule-library.yaml
techs/
typescript/
_group.yaml
narrow-unknown-values.md
model-valid-states.md
react/
_group.yaml
keep-state-local.md
name-interactive-controls.md
practices/
testing/
_group.yaml
verify-retry-limits.md
test-failure-paths.md
error-handling/
_group.yaml
preserve-error-context.md
make-errors-actionable.md
03 / APPLY

Make your rules part of your agent’s workflow.

Add instructions to your project’s AGENTS.md, or your agent’s equivalent, telling it where to find your rules and when to read them. Your agent uses those rules when writing and reviewing code.

See how agents use rules →
Your coding agentPROJECT SETUP

GIVE YOUR AGENT PROJECT INSTRUCTIONS

AGENTS.md

Use this project’s engineering rules.

Before writing or reviewing code, read
.code-rules/generated/RULES.md

Follow its instructions to select and read the rules that apply to your task.

What would you like to build?
Example setup. Use your coding agent’s project instruction file.
FROM THE FIELD

A wall of logic becomes a readable sequence.

While writing Code Rules, we prototyped it in TypeScript. An agent produced the Before example. This is what changed after we asked the agent to review it against our own rules.

Before

Parsing, validation, and collection intertwined
function licenseFiles(
  input: ReadonlyMap<string, string>,
  location: string,
): ReadonlyArray<string> {
  const library = object(
    json(
      requiredFile(input, 'rule-library.json', location),
      `${location}/rule-library.json`,
    ),
    location,
  );
  if (field(library, 'formatVersion') !== 1)
    return invalid(location, 'only library formatVersion 1 is supported');
  const rawLicense = field(library, 'license');
  if (rawLicense === undefined) return [];
  const license = object(rawLicense, `${location}.license`);
  const file = relativePath(
    nonempty(field(license, 'file'), `${location}.license.file`),
    location,
  );
  const notices = field(license, 'notices');
  if (!Array.isArray(notices))
    return invalid(location, 'license.notices must be an array');
  const paths = [
    file,
    ...notices.map((path: unknown) =>
      relativePath(nonempty(path, `${location}.license.notices`), location),
    ),
  ];
  for (const path of paths) requiredFile(input, path, location);
  return [...new Set(paths)].sort(compare);
}

After

Named steps, with an explicit contract
/**
 * Collect declared license and notice paths.
 * Return unique paths in code-unit order.
 * Return [] when no license is declared.
 * Throw BuildError for invalid input or missing files.
 */
export function collectLibraryLicensePaths(
  sourceFiles: ReadonlyMap<string, string>,
  sourceName: string,
): ReadonlyArray<string> {
  const manifest = libraryManifest(sourceFiles, sourceName);
  const declarations = licenseAndNoticeDeclarations(manifest, sourceName);
  requireDeclaredFiles(sourceFiles, declarations);
  const uniquePaths = new Set(declarations.map(({ path }) => path));
  return [...uniquePaths].sort(compare);
}

What changed

  • The contract is visible. The comment describes the result, empty case, and failures.
  • Names explain the steps. Understand the main steps without reading all the validation code.
  • Helpers own the details. Parsing, declarations, and file checks each have a focused function.
See the helper functions behind the “after”

Hello, fellow details nerd! 🤓 Ok, here are the helper functions behind the updated code.

/** @fileoverview Validates library license declarations and resolves their files within an in-memory source snapshot. */

import {
  compare,
  field,
  invalid,
  json,
  nonempty,
  object,
  relativePath,
  requiredFile,
} from './validation';

const LIBRARY_MANIFEST = 'rule-library.json';
const SUPPORTED_FORMAT_VERSION = 1;

/** A validated source-relative path paired with the manifest field that declared it for diagnostics. */
type DeclaredPath = {
  readonly path: string;
  readonly location: string;
};

/** Parse the library manifest into an object with a supported formatVersion, or throw BuildError. */
function libraryManifest(
  sourceFiles: ReadonlyMap<string, string>,
  sourceName: string,
): Record<string, unknown> {
  const location = `${sourceName}/${LIBRARY_MANIFEST}`;
  const text = requiredFile(sourceFiles, LIBRARY_MANIFEST, sourceName);
  const parsed = json(text, location);
  const manifest = object(parsed, location);
  if (field(manifest, 'formatVersion') !== SUPPORTED_FORMAT_VERSION) {
    return invalid(
      `${location}: formatVersion`,
      `only library formatVersion ${SUPPORTED_FORMAT_VERSION} is supported`,
    );
  }
  return manifest;
}

/** Validate a library file path and retain its location for error reporting. */
function declaredPath(value: unknown, location: string): DeclaredPath {
  const text = nonempty(value, location);
  return { path: relativePath(text, location), location };
}

/** Validate notice paths in declaration order, retaining indexed locations for diagnostics; throw BuildError for invalid entries. */
function noticePaths(
  value: unknown,
  location: string,
): ReadonlyArray<DeclaredPath> {
  if (!Array.isArray(value)) {
    return invalid(location, 'expected an array of notice paths');
  }
  const entries: ReadonlyArray<unknown> = value;
  return entries.map((entry, index) =>
    declaredPath(entry, `${location}[${index}]`),
  );
}

/**
 * Return the validated license path followed by notice paths in declaration order, retaining duplicates.
 * Return an empty array when licensing is unspecified; throw BuildError for an invalid declaration.
 */
function licenseAndNoticeDeclarations(
  manifest: Record<string, unknown>,
  sourceName: string,
): ReadonlyArray<DeclaredPath> {
  const value = field(manifest, 'license');
  if (value === undefined) return [];
  const location = `${sourceName}/${LIBRARY_MANIFEST}: license`;
  const license = object(value, location);
  const file = declaredPath(field(license, 'file'), `${location}.file`);
  const notices = noticePaths(field(license, 'notices'), `${location}.notices`);
  return [file, ...notices];
}

/** Throw BuildError at the first declaration whose path is absent from the snapshot; empty files count as present. */
function requireDeclaredFiles(
  sourceFiles: ReadonlyMap<string, string>,
  declarations: ReadonlyArray<DeclaredPath>,
): void {
  for (const { path, location } of declarations) {
    if (!sourceFiles.has(path)) {
      invalid(location, `missing declared file ${JSON.stringify(path)}`);
    }
  }
}

Historical example from src/builds/library-licenses.ts. The tool has since moved to Go and from JSON configuration to YAML. Later revisions added SPDX declarations and generated license metadata.

START WITH ONE PROJECT

Give your agents rules for good code

Choose your project’s rules, then set up your agents to use them when writing and validating code.

Walk through the setup
Fabrica Code RulesMIT licensed

Designed in California. Built with Fabrica.