All projects published/ · four things other people install

What I publish: code that becomes somebody else's dependency

Period
August 2026 · ongoing
Role
author and maintainer
Distribution
two npm packages, two Claude Code plugins
License
MIT on all four

What makes this different from the rest of the site

In the other case studies here the mistake shows up fast: somebody opens the system in the morning and it did not open. Here the mistake keeps a different schedule. Whoever installs a library is stuck with the design I picked, and the cost of my picking wrong only surfaces once changing it has already got expensive for them.

So the four blocks below say the same things in the same order: the problem, the decision that carries the value, the code that implements it, and the command you can run to check it without taking my word for anything.

lull: four messages, one reply

Someone types "hi", then "i wanted to ask", then "about the flat", then "the one downtown". Four webhooks, four model calls, four replies to a single question. The last three were written without knowing what the person was still typing.

The core is a pure reducer: state and event go in, new state and a list of effects come out. There is no timer and no network in there. That is why the same file compiled from src/core runs both in the browser demo and on the server, and it is what lets you test the behaviour without standing up Redis and without waiting on a clock.

src/core/reduce.ts see the whole file ↗
/** When the buffered turn is due: quiet silence, capped by maxWaitMs. */
export function deadline(state: ConversationState, policy: Policy): number {
  // Typing counts as activity, so a person still composing holds their turn
  // open. The cap below is what stops that from lasting forever.
  const lastActivity = Math.max(state.lastMessageAt, state.lastTypingAt ?? 0)
  const quiet = lastActivity + policy.quietMs
  const cap = (state.firstBufferedAt ?? state.lastMessageAt) + policy.maxWaitMs
  return Math.min(quiet, cap)
}

Across a thousand simulated conversations, typed the way people actually type, that is 71.3% fewer model calls: 20,888 messages became 6,000 turns. The command that reproduces the number is npm run bench, in the repository.

eventlaw: the same rule in three places

The same production rule usually exists three times: as an assertion in a test, as a query over recorded events, and as an alert in monitoring. The three disagree about deadlines, correlation keys and what an incomplete trace means. When one fails, what comes back is usually a boolean or a log dump, not the smallest sequence that explains the violation.

The law becomes serializable data instead of test code. One definition falsifies with generated input, verifies a recorded trace and monitors live events, because all three read the same structure. And the builder refuses a deadline that is not a finite, non-negative number at construction time rather than at evaluation time: a definition error shows up where it was written.

src/laws.ts see the whole file ↗
class EventuallyBuilder {
  constructor(
    private readonly trigger: EventPattern,
    private readonly consequent: EventPattern,
  ) {}

  within(withinMs: number): LawPattern {
    if (!Number.isFinite(withinMs) || withinMs < 0) {
      throw new Error('within must be a finite, non-negative number')
    }
    return new LawPattern({
      kind: 'eventually',
      trigger: this.trigger.ast,
      consequent: this.consequent.ast,
      withinMs,
    })
  }
}

It is a public beta, and this page says so rather than hiding it: the core is tested, and independent API validation is still in progress. What is stable and what is not is declared in docs/stability.md. Install it with npm install eventlaw@beta.

anti-slop: 49 marks of work nobody finished

An interface that came out generic has a repeating symptom: the palette nobody picked, the dark theme nobody opened, the copy nobody wrote, the setting nobody set. None of that proves a model wrote the code. It proves nobody came back to it.

The two skills are one loop. The auditor suppresses a false positive when it finds evidence that somebody chose the value, and the build skill writes into exactly the four places the auditor looks for that evidence. A tell firing on a tree the build skill produced is the build skill's failure, and it arrives with a file and a line. Every catalog entry is also required to carry four fields, one of them the case where it does not apply, which is the part such lists usually skip. What enforces that is a script, not the goodwill of whoever is writing.

scripts/validate.py see the whole file ↗
def check_tells(text, source):
    """Report every tell in the text that is missing one of the four fields.

    Containment is by substring, so the fields are accepted in any order and
    anywhere in the tell's body. This check does not police their sequence.
    """
    tells = collect_tells(text)
    if not tells:
        return ["{}: no tells found".format(source)]
    return [
        "{}: {} is missing {}".format(source, tell_id, field)
        for tell_id, tell in tells.items()
        for field in FIELDS
        if field not in tell["body"]
    ]

Forty-nine tells across five axes: twelve on surface, fifteen on craft, three on states, seven on words and twelve on finish. The script above is what stops the catalog from growing without them.

merge-odds: read the rules before touching the repo

Maintainers spend hours closing pull requests nobody asked for, many of them written by agents that never opened the file where the project explains its own rules. Those files exist: a pull request template, an AI policy, a contribution guide.

Every claim in the dataset carries a verbatim quote, with a link pinned to the commit where it was read. The quoted text is a literal slice of the file, cropped only by length, never re-indented or rewritten. And a field's default value means "no restriction found in the files read", never "the project granted permission". Reading the default as permission is the mistake that gets somebody to open a pull request on a project that never said it takes them.

src/merge_odds/policy.py see the whole file ↗
def _block_around(lines: list[str], index: int) -> tuple[int, int]:
    start = index
    while start > 0 and lines[start - 1].strip():
        start -= 1
    end = index
    while end < len(lines) - 1 and lines[end + 1].strip():
        end += 1
    if end - start + 1 > QUOTE_MAX_LINES:
        start, end = index, min(index + QUOTE_MAX_LINES - 1, len(lines) - 1)
    return start, end

Eight projects measured so far, and two skills answering two questions in order: vet-repo says whether the project takes outside work and under what rules, and vet-issue says whether that particular task is still available. An issue can be open, unassigned and referenced by no pull request while the defect it describes has already been fixed.

And what I send to other people's projects

This page is what I publish. The other side, my fixes landing in projects that are not mine and going through review by a maintainer who does not know me, has its own page: open source.