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

dot-git-ci

v0.1.2

Published

Portable CI/CD over docker, with results stored in git

Readme

git-ci

Portable CI/CD that runs anywhere docker runs, with all results stored in git. No vendor lock-in to GitHub Actions / GitLab CI / Jenkins. The repository is the single source of truth for code, deploy state, build logs, and test history.

Philosophy

  • One source of truth: the git repo. Code, env compositions, logs, deploy state — all live in branches.
  • No central service: anything git-ci does, you can also do by hand with git, ssh, rsync, docker compose.
  • Each project is self-contained: no group/multi-repo logic baked in. If you have several related repos, you run git-ci in each.
  • Docker as the only runtime dependency on the host. The local CLI is Node ≥18.

Mental model

main              canonical .git-ci/*.yml definitions (env shapes, gates)
feat/*            may carry their own .git-ci/config.yml (how-to-test)
ci-state          orphan branch: concrete state — which branches are mixed into each env
ci-logs           orphan branch: all run/promote/deploy/demote logs, streamed every 5s

Two deploy transports, picked per command:

| command | source of state | transport | branch mix | |---|---|---|---| | run | workdir | local docker | none | | deploy [env] | workdir | rsync + ssh | none | | promote <env> [branch] | git origin | ssh + host-side git fetch | on host | | demote <env> [branch] | git origin | ssh + host-side git fetch | on host | | install <user@host> | — | ssh setup | — |

Quick start

# install
cd ~/okneigres-repos/git-ci
./install.sh                 # symlinks git-ci + gci into ~/.local/bin
# or:
npm install -g .

# in your project
mkdir -p .git-ci
cat > .git-ci/config.yml <<'EOF'
service: app
run: npm test
EOF

# run tests locally inside docker
git-ci run

# prepare a remote host
git-ci install [email protected]

# describe an environment (on main)
cat > .git-ci/preprod.yml <<'EOF'
host: [email protected]
service: app
protected: true
gates:
  - tests-passed
EOF
git add .git-ci/preprod.yml && git commit -m "add preprod env"

# promote a feature into preprod
git checkout feat/login
git-ci promote preprod         # appends feat/login to preprod.yml on ci-state branch,
                               # then ssh's the host and rebuilds the env from scratch

Commands

| command | what it does | |---|---| | run | reads .git-ci/config.yml, runs docker compose build <service> && docker compose run --rm <service> sh -c <run>. Local-only by default. | | deploy [env] | rsync current workdir + sibling repos to <env>'s host under ~/.git-ci/<project>/deploy/<env>/, docker compose -p <project>-<env> up -d --build there. No branch mix. Refuses on protected: true envs. | | promote <env> [branch] | append branch to ci-state:<env>.yml, ssh host, fetch + merge branches in order, rebuild. Gates from <env>.yml are checked first. | | demote <env> [branch] | remove branch from ci-state:<env>.yml, rebuild without it. | | install <user@host> | ensure docker/git/rsync on host, clone repo into ~/.git-ci/<project>/repo, prepare workdir. |

Sibling projects

A project may pull in code from sibling project dirs by symlinking them under node_modules/:

~/my-group/
  ├─ project-a/                       # current project (we deploy this)
  │   ├─ docker-compose.yml           # build.context: ..
  │   └─ node_modules/
  │       └─ lib-b -> ../../lib-b     # symlink to sibling
  └─ lib-b/                           # sibling — copied to host but not run

git-ci deploy detects these symlinks (target starts with ../../) and rsyncs each sibling to the host alongside the current project. They are placed as static files only — not built, not run — so the current project's docker-compose.yml can reference them via build.context: .. or similar. This is the same convention used by ../rsync-docker-compose.

Remote layout under ~/.git-ci/<project>/deploy/<env>/:

~/.git-ci/project-a/deploy/feat-login/
  ├─ project-a/        # current
  └─ lib-b/            # sibling (static)

Stale sibling dirs (no longer in node_modules) are cleaned up on next deploy.

Config files

.git-ci/config.yml — read from the current branch, describes how to test/build that branch.

service: app                   # name from docker-compose.yml
run: npm ci && npm test        # shell command inside the container

.git-ci/<env>.yml — read from the canonical branch (main, falling back to master), describes the shape of an environment. deploy also accepts a workdir copy; promote/demote are strict.

host: [email protected]
service: app
protected: true                # disallow `git-ci deploy <env>`; only promote/demote can change it
gates:
  - tests-passed               # branch must have a successful ci-logs entry on the env's build commit
  - in-env: preprod            # (on prod.yml) branch must currently be in preprod
env:
  DATABASE_URL: postgres://...
  PUBLIC_URL: https://preprod.example.com

.git-ci/[branch].yml — template, rendered per branch. {{branch_slug}} expands to the branch name with /-.

host: [email protected]
service: app
env:
  PUBLIC_URL: https://{{branch_slug}}.preview.example.com
  DATABASE_URL: postgres://.../{{branch_slug}}_db
ttl: 7d

Status

Implemented: run, install, deploy (with [branch].yml template fallback and live file watcher). Not yet: promote, demote, and the ci-logs / ci-state plumbing. See AGENTS.md for the architecture invariants.

License

MIT.