npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@supersuit/friend-md

v0.2.0

Published

Read, write, validate and convert portable friend.md relationship records.

Readme

@supersuit/friend-md

Read, write, validate and convert relationship records stored as Markdown. A small friend.md portrait sits beside append-only history, stories and quotes. This package carries the existing JavaScript implementation and its Python companion, without a Freedom installation or runtime npm dependencies.

Node 22 or later is required. Python 3.9 or later is needed only for the companion. Use is governed by the retained Continental Works license.

Install

npm install @supersuit/friend-md

Read a person

Functions taking dir expect the people directory itself. peopleDir(root) maps an explicit workspace root to that directory. Without a root, it uses the working directory and never discovers a global Freedom installation.

import { peopleDir, resolve, readPerson } from '@supersuit/friend-md';

const dir = peopleDir(process.cwd());
const slug = resolve(dir, 'Annie');
if (slug) {
  const person = readPerson(dir, slug, { sections: ['Now', 'How I talk to them'] });
  console.log(person.data.name, person.sections);
}

Folder records take precedence over flat records. Archived people are supported. Resolution checks slug, phone, address, name, alias and handle in order. An ambiguous match throws AmbiguousPerson with its candidates; a missing person returns null. readPerson joins sections from the portrait, story.md and quotes.md.

Write history

import { ensure, appendLog, setLastContact, peopleDir } from '@supersuit/friend-md';

const dir = peopleDir(process.cwd());
ensure(dir, 'ann-lee', { name: 'Ann Lee' });
appendLog(dir, 'ann-lee', {
  date: '2026-10-04',
  line: 'Planned the next tea gathering',
  source: 'meeting-notes/tea.md',
});
setLastContact(dir, 'ann-lee', {
  date: '2026-10-04',
  how: 'call',
  about: 'tea gathering',
});

ensure creates exclusively and leaves existing records intact. New folder records require layout: friend-md in the people directory's README.md, or an existing folder record. Otherwise new records use the supported legacy flat layout. appendLog writes a dated, sourced line to log/YYYY-MM.md for folder records and to a named section for flat records. setLastContact operates on folder records.

CLI

npx friend-md --help
npx friend-md list --people ./people --json
npx friend-md resolve Annie --people ./people --json
npx friend-md read ann-lee --people ./people --sections Now --json
npx friend-md lint --people ./people

Commands: read, list, path, resolve, operator, lint. Use --workspace DIR for a root containing people/ and self/; this also honors local .freedom.json paths.people, paths.self and paths.user overrides. Paths may be relative to the root or absolute. No global configuration is read. operator reads the root's self/self.md, with the existing legacy user/USER.md and self-record fallback.

--paths, --no-phone and --no-contact filter lists. --prompt renders selected sections for an agent. --json produces machine-readable output.

Exit codes: 0 success or lint warnings only; 1 missing record, lint error or runtime refusal; 2 malformed CLI arguments or an ambiguous match.

Validate or convert a record

import { lint, migratePerson } from '@supersuit/friend-md';

const findings = lint('./people');
const conversion = migratePerson(legacyMarkdown, {
  slug: 'ann-lee',
  day: '2026-10-04',
});
if (conversion.proof.unaccounted.length) {
  throw new Error('Record conversion refused; inspect the proof before writing files');
}
// conversion.files maps relative filenames to text. The caller controls applying them.

migratePerson, migrateGroup, transcriptResolver and verifyMigration provide record-level conversion and proof. Whole-workspace migration, Git locking, link rewriting, OS message capture and self-folder conversion remain in Freedom. This release does not switch Freedom's deployed implementation to an npm dependency.

The format reference describes files, required fields and limits.

The relationship vocabulary (FACETS) is a default, not a closed list. A workspace adds its own facets in people/README.md under a ## Facets heading, one - name: what it means line each; lint reads them (declaredFacets(dir)) and stops warning about them. The package also exports its existing vocabulary, normalization and path helpers; src/index.mjs carries their signatures and contract comments.

Python companion

The companion implements the existing directory, header, resolution and writer functions using the Python standard library. JavaScript owns lint and conversion. Find the installed asset through the package's explicit subpath:

node --input-type=module -e "import {createRequire} from 'node:module'; console.log(createRequire(import.meta.url).resolve('@supersuit/friend-md/python'));"

Add the printed file's parent directory to sys.path, then import freedom_people. The import name is retained for compatibility; npm does not install a Python package into a virtual environment. Shared synthetic fixtures verify JavaScript/Python parity.

Development and release

npm ci
npm test
npm run test:package

test:package packs the real payload, installs it into a clean external consumer, and runs the API, installed CLI and Python asset there. Tests and fixtures stay out of the published tarball. SOURCE.json records the pinned extraction inputs and adaptations.

The initial release uses npm web approval. Subsequent releases use the tag-triggered GitHub Actions workflow and an npm trusted publisher. Commit the lockfile with each version change and the matching changelog, then push a v<version> tag. No npm token belongs in the repository or workflow.