@repokit/core
v2.1.0
Published
A knowledgebase for your repository - wrapped in a CLI
Downloads
1,663
Maintainers
Readme
repokit
A knowledgebase for your repository - wrapped in a CLI.
Repokit is designed for large teams in complex codebases to publish self-documenting commands, API's, and workflows to a central CLI.
The Repokit CLI exists as a living source of documentation and knowledge - growing alongside your team.
Getting Started
Installation
If you do not have node.js setup in your repository, you'll first want to install node.js.
NVM is a popular posix compliant installer
Once installed, you can run the following in the root of your repository
npm initIf you don't have typescript already setup in your repository, you can run:
npm i -D typescript && tsc --initNext, install repokit:
npm i -D @repokit/core
# or
yarn add -D @repokit/core
# or
pnpm add -D @repokit/coreOnce installed, run
repokitRepokit will create a config file named repokit.ts on your first run. Fill out this file with your desired settings.
Here's an example of what our intenral Repokit config looks like:
import { RepoKitConfig } from "@repokit/core";
export const RepoKit = new RepoKitConfig({
project: "Repokit",
commands: {
"build:rust": {
command: "cargo build --release",
description: "Build CLI in production mode",
},
"install:rust": {
command: "cargo install --path .",
description: "Installs the production CLI and adds it to your path",
},
"lint:ts": {
command:
"yarn oxlint --type-aware --type-check --report-unused-disable-directives --fix && yarn oxfmt",
description: "Lints typescript files using oxc",
},
},
});Commands in your config file are optional, but in your repokit.ts config is a good place to store any commonly run commands that aren't specific to any library or package in your repository.
To verify your configuration, run
repokitThe CLI will list out its internal commands as well as any commands you registered in your config file.
Next run:
repokit onboardBuilding Your CLI
To begin building your CLI, run:
repokit register ./path/to/your/featureThis command generates a tool definition for your feature that you can fill out using your tool's API's. A tool definition might look something like the following:
import { RepoKitCommand } from "@repokit/core";
export const Commands = new RepoKitCommand({
name: "user-interface",
description: "Build commands for the UI",
commands: {
"build:production": {
command: "vite build",
description: "Build the UI for production",
args: {
"(--optimization | -o)":
"Run post-build optimizers such as compression and css purging",
},
},
"run:development": {
command: "vite",
description: "Run the UI in development mode",
args: {
"(--port | -p)":
"Specifies the port number to run the development server on",
"(--open | -o)": "Opens your OS' preferred browser",
},
},
},
});When finished with your definition, save the file and run:
repokit user-interfaceThe CLI will list out your new tool's API's:
To invoke any of them, run:
repokit user-interface <sub-command> <args>Reasoning about your toolchain
As your toolchain grows it's possible to find yourself with hundreds, if not thousands of registered commands.
To make reasoning about your commands easier, there are a few internal commands worth getting to know
repokit search
repokit search is a blanket search over all command definitions. Using it you can search for commands by name, owner, definition, location, or even the tools that it invokes.
For example, let's say you wanted to list all commands that invoke cargo, you could run
repokit search cargoIf you wanted to search for all commands owned by an individual or team you could run
repokit search <person or team name>If you wanted to search for commands under a given path you could run
repokit search path/within/your/codebaseYou can query for just about anything you can imagine
repokit locate
Code changes can sometimes require updating command definitions. Repokit can easily locate any command's definition by name:
repokit locate <your-tool-name>repokit owners
If your team makes use of the owners attribute when defining your commands, you can easily list all commands owned by an individual or team
repokit list <owner>repokit list can also accept internal | registered | root as an argument.
internal will cause repokit to list out all of its internal commands
registered will cause repokit to list out all of the commands your team has defined around your codebase
root will cause repokit to list out all commands in your repokit.ts config
Best Practices for Registering Commands
First and most simply - use verbose descriptions. Document flags, positionals, and environment variables required to invoke your tool.
If your tool requires arguments, abstract common combinations of arguments into their own sub-commands. For example, instead of a single build command requiring flags to configure it, create sub commands that abstract commonly used combinations of parameters:
import { RepoKitCommand } from "@repokit/core";
export const Commands = new RepoKitCommand({
// ... command definition
commands: {
"build:local": {
command: "bazel build --env development",
description: "Builds in development mode",
},
"build:production": {
command: "bazel build --progress --stats --env production",
description: "Builds in production mode",
},
},
});When possible, prefer flags and positionals over environment variables. Often times your argv parsers will provide some out-of-the-box validations for free that environment variables simply don't get.
Working Directories
The commands you register onto the repokit toolchain will always be invoked using the working directory of the command's definition.
If your command needs to reason about the file system, keep this in mind.
Themes
The Repokit CLI can be customized to support themes that better match your team's visual preferences.
Repokit comes with 4 pre-built themes that you can use in your RepoKitConfig.
import {
RepoKitConfig,
SeeingRed, // A red theme
TheBlues, // A blue theme
Green, // A green theme
} from "@repokit/core";
export const Kit = new RepoKitConfig({
project: "My Project",
theme: SeeingRed, // Specify a theme here
});By omitting the theme property RepoKit will use its default visuals.
In addition to built-in themes, you can create your own using the RepoKitTheme
import { RepoKitConfig, RepoKitTheme } from "@repokit/core";
export const Kit = new RepoKitConfig({
project: "My Project",
theme: new RepoKitTheme({
prefixColor: "rgb(220, 36, 91)",
commandColor: "rgb(220, 36, 36)",
subcommandColor: "rgb(220, 131, 36)",
argColor: "rgb(220, 205, 36)",
descriptionColor: "rgb(179, 100, 151)",
errorPrefixColor: "rgb(220, 36, 39)",
highlightColor: "rgb(237, 175, 41)",
}),
});All properties on the RepoKitTheme are optional overrides for RepoKit's default styling. A color can be any CSS-valid rgb() string.
Motivation
I worked in a codebase at Google that used just about every programming language in existence. Each team had their own methodology for exposing commands, scripts, and API's for their team's day-to-day development needs.
Some teams used shell scripts, some used a tool called bazel, and some relied on good old python ./path/to/my-script.py (or something similar).
For engineers new and old to onboard to new features, they were often left stuck combing through these undocumented scripts and tools - tracking down environment variables, positionals, and flags to get necessary commands to succeed.
Most of the time landing them in GChat asking for help.
During my time there, I never met an engineer with a fully functioning local environment.
It was there that I designed an early version repokit.
