rename OpenClaw tools flake

Move the flake identity from nix-steipete-tools to nix-openclaw-tools, update transferred upstream repos to openclaw, and drop stale CodexBar/bird packaging.

Tests: go test ./...; nix flake show --all-systems; nix build .#gogcli .#goplaces .#summarize .#camsnap .#sonoscli --no-link
This commit is contained in:
joshp123 2026-05-05 12:04:06 +02:00
parent 76bccdda2d
commit 675f4ba420
31 changed files with 65 additions and 543 deletions

View File

@ -17,7 +17,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Sync skills from clawdbot - name: Sync skills from OpenClaw
run: go run ./cmd/sync-skills run: go run ./cmd/sync-skills
- name: Commit & push if changed - name: Commit & push if changed
@ -26,8 +26,8 @@ jobs:
echo "No changes" echo "No changes"
exit 0 exit 0
fi fi
git config user.name "clawdbot-ci" git config user.name "openclaw-ci"
git config user.email "ci@clawdbot" git config user.email "ci@openclaw.local"
git add -A git add -A
git commit -m "sync skills from clawdbot" git commit -m "sync skills from openclaw"
git push git push

View File

@ -31,8 +31,8 @@ jobs:
echo "No changes" echo "No changes"
exit 0 exit 0
fi fi
git config user.name "clawdbot-ci" git config user.name "openclaw-ci"
git config user.email "ci@clawdbot" git config user.email "ci@openclaw.local"
git add -A git add -A
git commit -m "update tool releases" git commit -m "update tool releases"
git push git push

View File

@ -1,15 +1,15 @@
# nix-steipete-tools # nix-openclaw-tools
> Core tools for openclaw. Batteries included. Always fresh. > Reproducible OpenClaw tool packaging.
Nix packaging for [Peter Steinberger's](https://github.com/steipete) tools, with per-tool openclaw plugins. Part of the [nix-openclaw](https://github.com/openclaw/nix-openclaw) ecosystem. Nix packaging for OpenClaw-adjacent tools, with per-tool OpenClaw plugin metadata. Part of the [nix-openclaw](https://github.com/openclaw/nix-openclaw) ecosystem.
Darwin/aarch64 plus Linux (x86_64/aarch64) for tools that ship Linux builds. Darwin/aarch64 plus Linux (x86_64/aarch64) for tools that ship Linux builds.
On Linux, `summarize` is built from source (Node 22 + pnpm) since upstream only ships a macOS Bun binary. On Linux, `summarize` is built from source (Node 22 + pnpm) since upstream only ships a macOS Bun binary.
## Why this exists ## Why this exists
These tools are essential for a capable openclaw instance - screen capture, camera access, TTS, messaging. Packaging them as Nix flakes with openclaw plugin metadata means: OpenClaw should have a small default toolchain and explicit optional plugins. Packaging these tools as Nix flakes with OpenClaw plugin metadata means:
- **Reproducible**: Pinned versions, no Homebrew drift - **Reproducible**: Pinned versions, no Homebrew drift
- **Declarative**: Add a plugin, `home-manager switch`, done - **Declarative**: Add a plugin, `home-manager switch`, done
@ -34,17 +34,16 @@ Homebrew configuration, not in these pure Nix package/module definitions.
| Tool | What it does | | Tool | What it does |
|------|--------------| |------|--------------|
| [**summarize**](https://github.com/steipete/summarize) | Link → clean text → summary | | [**summarize**](https://github.com/steipete/summarize) | Link → clean text → summary |
| [**discrawl**](https://github.com/steipete/discrawl) | Mirror Discord into SQLite and search history locally | | [**discrawl**](https://github.com/openclaw/discrawl) | Mirror Discord into SQLite and search history locally |
| [**wacrawl**](https://github.com/steipete/wacrawl) | Read-only local archive and search for WhatsApp Desktop data | | [**wacrawl**](https://github.com/steipete/wacrawl) | Read-only local archive and search for WhatsApp Desktop data |
| [**gogcli**](https://github.com/steipete/gogcli) | Google CLI for Gmail, Calendar, Drive, and Contacts | | [**gogcli**](https://github.com/openclaw/gogcli) | Google CLI for Gmail, Calendar, Drive, and Contacts |
| [**goplaces**](https://github.com/steipete/goplaces) | Google Places API (New) CLI | | [**goplaces**](https://github.com/openclaw/goplaces) | Google Places API (New) CLI |
| [**camsnap**](https://github.com/steipete/camsnap) | Capture snapshots/clips from RTSP/ONVIF cameras | | [**camsnap**](https://github.com/steipete/camsnap) | Capture snapshots/clips from RTSP/ONVIF cameras |
| [**sonoscli**](https://github.com/steipete/sonoscli) | Control Sonos speakers | | [**sonoscli**](https://github.com/steipete/sonoscli) | Control Sonos speakers |
| [**peekaboo**](https://github.com/steipete/peekaboo) | Lightning-fast macOS screenshots & AI vision analysis | | [**peekaboo**](https://github.com/openclaw/Peekaboo) | Lightning-fast macOS screenshots & AI vision analysis |
| [**poltergeist**](https://github.com/steipete/poltergeist) | Universal file watcher with auto-rebuild | | [**poltergeist**](https://github.com/steipete/poltergeist) | Universal file watcher with auto-rebuild |
| [**sag**](https://github.com/steipete/sag) | Command-line ElevenLabs TTS with mac-style flags | | [**sag**](https://github.com/steipete/sag) | Command-line ElevenLabs TTS with mac-style flags |
| [**imsg**](https://github.com/steipete/imsg) | iMessage/SMS CLI | | [**imsg**](https://github.com/openclaw/imsg) | iMessage/SMS CLI |
| [**CodexBar**](https://github.com/steipete/CodexBar) | macOS menu bar app for Codex, Claude, and other provider usage |
## Usage (as openclaw plugins) ## Usage (as openclaw plugins)
@ -52,11 +51,11 @@ Each tool is a subflake under `tools/<tool>/` exporting `openclawPlugin`. Point
```nix ```nix
programs.openclaw.plugins = [ programs.openclaw.plugins = [
{ source = "github:openclaw/nix-steipete-tools?dir=tools/camsnap"; } { source = "github:openclaw/nix-openclaw-tools?dir=tools/camsnap"; }
{ source = "github:openclaw/nix-steipete-tools?dir=tools/discrawl"; } { source = "github:openclaw/nix-openclaw-tools?dir=tools/discrawl"; }
{ source = "github:openclaw/nix-steipete-tools?dir=tools/peekaboo"; } { source = "github:openclaw/nix-openclaw-tools?dir=tools/peekaboo"; }
{ source = "github:openclaw/nix-steipete-tools?dir=tools/summarize"; } { source = "github:openclaw/nix-openclaw-tools?dir=tools/summarize"; }
{ source = "github:openclaw/nix-steipete-tools?dir=tools/wacrawl"; } { source = "github:openclaw/nix-openclaw-tools?dir=tools/wacrawl"; }
]; ];
``` ```
@ -70,57 +69,21 @@ Each plugin bundles:
If you just want the binaries without the plugin wrapper: If you just want the binaries without the plugin wrapper:
```nix ```nix
inputs.nix-steipete-tools.url = "github:openclaw/nix-steipete-tools"; inputs.nix-openclaw-tools.url = "github:openclaw/nix-openclaw-tools";
# Then use: # Then use:
inputs.nix-steipete-tools.packages.aarch64-darwin.camsnap inputs.nix-openclaw-tools.packages.aarch64-darwin.camsnap
inputs.nix-steipete-tools.packages.aarch64-darwin.discrawl inputs.nix-openclaw-tools.packages.aarch64-darwin.discrawl
inputs.nix-steipete-tools.packages.aarch64-darwin.peekaboo inputs.nix-openclaw-tools.packages.aarch64-darwin.peekaboo
inputs.nix-steipete-tools.packages.aarch64-darwin.wacrawl inputs.nix-openclaw-tools.packages.aarch64-darwin.wacrawl
inputs.nix-steipete-tools.packages.aarch64-darwin.codexbar-app
# etc. # etc.
# Linux examples: # Linux examples:
inputs.nix-steipete-tools.packages.x86_64-linux.camsnap inputs.nix-openclaw-tools.packages.x86_64-linux.camsnap
inputs.nix-steipete-tools.packages.x86_64-linux.discrawl inputs.nix-openclaw-tools.packages.x86_64-linux.discrawl
inputs.nix-steipete-tools.packages.aarch64-linux.gogcli inputs.nix-openclaw-tools.packages.aarch64-linux.gogcli
inputs.nix-steipete-tools.packages.x86_64-linux.summarize inputs.nix-openclaw-tools.packages.x86_64-linux.summarize
inputs.nix-steipete-tools.packages.x86_64-linux.wacrawl inputs.nix-openclaw-tools.packages.x86_64-linux.wacrawl
```
### Home Manager modules
Some packages also ship Home Manager modules so they can be enabled directly
without hand-writing install and launchd wiring. For CodexBar:
```nix
{
imports = [ inputs.nix-steipete-tools.homeManagerModules.codexbar ];
programs.codexbar.enable = true;
}
```
That adds the CodexBar app package to `home.packages`. Home Manager can then
expose the app bundle through its Darwin app targets. If you want Home Manager
to own startup too, enable the launchd agent explicitly:
```nix
{
programs.codexbar = {
enable = true;
launchd.enable = true;
launchd.keepAlive = false;
};
}
```
### macOS app bundles
If you only want the raw app package, use the package output directly:
```nix
inputs.nix-steipete-tools.packages.aarch64-darwin.codexbar-app
``` ```
## Skills syncing ## Skills syncing
@ -151,13 +114,7 @@ Fetches latest release versions/URLs/hashes and updates the Nix expressions.
| **update-tools** | Every 10 min | Checks for new tool releases | | **update-tools** | Every 10 min | Checks for new tool releases |
| **Garnix** | On push | Builds all packages via `checks.*` (darwin + linux) | | **Garnix** | On push | Builds all packages via `checks.*` (darwin + linux) |
Automated PRs keep everything fresh without manual intervention. Automation commits directly when versions or skills change.
## Temporarily disabled
`bird` is not exported right now because the upstream GitHub release assets for
v0.8.0 are gone. The npm package still exists, but this flake does not currently
build npm dependencies for it.
## License ## License

View File

@ -52,7 +52,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
workdir, err := os.MkdirTemp("", "clawdbot-skills-") workdir, err := os.MkdirTemp("", "openclaw-skills-")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -70,8 +70,8 @@ func main() {
{"imsg", "skills/imsg"}, {"imsg", "skills/imsg"},
} }
log.Printf("[sync-skills] cloning clawdbot main") log.Printf("[sync-skills] cloning openclaw main")
if err := run("", "git", "clone", "--depth", "1", "--filter=blob:none", "--sparse", "https://github.com/clawdbot/clawdbot.git", workdir); err != nil { if err := run("", "git", "clone", "--depth", "1", "--filter=blob:none", "--sparse", "https://github.com/openclaw/openclaw.git", workdir); err != nil {
log.Fatal(err) log.Fatal(err)
} }
paths := []string{} paths := []string{}

View File

@ -9,7 +9,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"github.com/clawdbot/nix-steipete-tools/internal" "github.com/openclaw/nix-openclaw-tools/internal"
) )
type Tool struct { type Tool struct {
@ -149,7 +149,7 @@ func main() {
tools := []Tool{ tools := []Tool{
{ {
Name: "discrawl", Name: "discrawl",
Repo: "steipete/discrawl", Repo: "openclaw/discrawl",
Assets: []AssetSpec{ Assets: []AssetSpec{
{System: "aarch64-darwin", Regex: regexp.MustCompile(`discrawl_[0-9.]+_darwin_arm64\.tar\.gz`)}, {System: "aarch64-darwin", Regex: regexp.MustCompile(`discrawl_[0-9.]+_darwin_arm64\.tar\.gz`)},
{System: "x86_64-linux", Regex: regexp.MustCompile(`discrawl_[0-9.]+_linux_amd64\.tar\.gz`)}, {System: "x86_64-linux", Regex: regexp.MustCompile(`discrawl_[0-9.]+_linux_amd64\.tar\.gz`)},
@ -169,7 +169,7 @@ func main() {
}, },
{ {
Name: "gogcli", Name: "gogcli",
Repo: "steipete/gogcli", Repo: "openclaw/gogcli",
Assets: []AssetSpec{ Assets: []AssetSpec{
{System: "aarch64-darwin", Regex: regexp.MustCompile(`gogcli_[0-9.]+_darwin_arm64\.tar\.gz`)}, {System: "aarch64-darwin", Regex: regexp.MustCompile(`gogcli_[0-9.]+_darwin_arm64\.tar\.gz`)},
{System: "x86_64-linux", Regex: regexp.MustCompile(`gogcli_[0-9.]+_linux_amd64\.tar\.gz`)}, {System: "x86_64-linux", Regex: regexp.MustCompile(`gogcli_[0-9.]+_linux_amd64\.tar\.gz`)},
@ -179,7 +179,7 @@ func main() {
}, },
{ {
Name: "goplaces", Name: "goplaces",
Repo: "steipete/goplaces", Repo: "openclaw/goplaces",
Assets: []AssetSpec{ Assets: []AssetSpec{
{System: "aarch64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_arm64\.tar\.gz`)}, {System: "aarch64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_arm64\.tar\.gz`)},
{System: "x86_64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_amd64\.tar\.gz`)}, {System: "x86_64-darwin", Regex: regexp.MustCompile(`goplaces_[0-9.]+_darwin_amd64\.tar\.gz`)},
@ -210,7 +210,7 @@ func main() {
}, },
{ {
Name: "peekaboo", Name: "peekaboo",
Repo: "steipete/peekaboo", Repo: "openclaw/Peekaboo",
Assets: []AssetSpec{ Assets: []AssetSpec{
{System: "aarch64-darwin", Regex: regexp.MustCompile(`peekaboo-macos-(?:arm64|universal)\.tar\.gz`)}, {System: "aarch64-darwin", Regex: regexp.MustCompile(`peekaboo-macos-(?:arm64|universal)\.tar\.gz`)},
}, },
@ -235,7 +235,7 @@ func main() {
}, },
{ {
Name: "imsg", Name: "imsg",
Repo: "steipete/imsg", Repo: "openclaw/imsg",
Assets: []AssetSpec{ Assets: []AssetSpec{
{System: "aarch64-darwin", Regex: regexp.MustCompile(`imsg-macos\.zip`)}, {System: "aarch64-darwin", Regex: regexp.MustCompile(`imsg-macos\.zip`)},
}, },

View File

@ -1,5 +1,5 @@
{ {
description = "Nix packaging for steipete tools (clawdbot)"; description = "Nix packaging for OpenClaw tools";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
@ -22,7 +22,6 @@
poltergeist = [ "aarch64-darwin" ]; poltergeist = [ "aarch64-darwin" ];
sag = [ "aarch64-darwin" "x86_64-linux" ]; sag = [ "aarch64-darwin" "x86_64-linux" ];
imsg = [ "aarch64-darwin" ]; imsg = [ "aarch64-darwin" ];
codexbar-app = [ "aarch64-darwin" ];
}; };
in { in {
packages = forAllSystems (system: packages = forAllSystems (system:
@ -67,16 +66,8 @@
// (lib.optionalAttrs (supports "imsg") { // (lib.optionalAttrs (supports "imsg") {
imsg = pkgs.callPackage ./nix/pkgs/imsg.nix {}; imsg = pkgs.callPackage ./nix/pkgs/imsg.nix {};
}) })
// (lib.optionalAttrs (supports "codexbar-app") {
codexbar-app = pkgs.callPackage ./nix/pkgs/codexbar-app.nix {};
})
); );
homeManagerModules = {
codexbar = import ./nix/modules/home-manager/codexbar.nix { inherit self; };
default = self.homeManagerModules.codexbar;
};
checks = forAllSystems (system: self.packages.${system}); checks = forAllSystems (system: self.packages.${system});
}; };
} }

2
go.mod
View File

@ -1,3 +1,3 @@
module github.com/clawdbot/nix-steipete-tools module github.com/openclaw/nix-openclaw-tools
go 1.22 go 1.22

View File

@ -1,88 +0,0 @@
{ self }:
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkEnableOption mkIf mkOption types;
cfg = config.programs.codexbar;
system = pkgs.stdenv.hostPlatform.system;
defaultPackage =
if self.packages ? ${system} && self.packages.${system} ? codexbar-app then
self.packages.${system}.codexbar-app
else
null;
in
{
options.programs.codexbar = {
enable = mkEnableOption "CodexBar macOS menu bar app";
package = mkOption {
type = types.nullOr types.package;
default = defaultPackage;
defaultText = lib.literalExpression "inputs.nix-steipete-tools.packages.\${pkgs.system}.codexbar-app";
description = "CodexBar app package.";
};
launchd = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Configure a launchd agent to manage the CodexBar process.
CodexBar can also manage launch-at-login from inside the app. Enable this
option when you want Home Manager and launchd to own startup instead.
'';
};
keepAlive = mkOption {
type = types.bool;
default = false;
description = "Whether launchd should restart CodexBar after it exits.";
};
environmentVariables = mkOption {
type = types.attrsOf types.str;
default = {
PATH = "${config.home.profileDirectory}/bin:/usr/bin:/bin:/usr/sbin:/sbin";
};
defaultText = lib.literalExpression ''
{
PATH = "\${config.home.profileDirectory}/bin:/usr/bin:/bin:/usr/sbin:/sbin";
}
'';
description = "Environment variables passed to the CodexBar launchd agent.";
};
};
};
config = mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "programs.codexbar" pkgs lib.platforms.darwin)
{
assertion = cfg.package != null;
message = "programs.codexbar.package must be set on this platform.";
}
{
assertion = !cfg.launchd.enable || config.launchd.enable;
message = "programs.codexbar.launchd.enable requires launchd.enable.";
}
];
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
launchd.agents.codexbar = mkIf cfg.launchd.enable {
enable = true;
config = {
ProgramArguments = [ "${cfg.package}/Applications/CodexBar.app/Contents/MacOS/CodexBar" ];
ProcessType = "Interactive";
RunAtLoad = true;
KeepAlive = cfg.launchd.keepAlive;
EnvironmentVariables = cfg.launchd.environmentVariables;
};
};
};
}

View File

@ -1,39 +0,0 @@
{ lib, stdenv, fetchurl }:
let
sources = {
"aarch64-darwin" = {
url = "https://github.com/steipete/bird/releases/download/v0.8.0/bird-macos-universal-v0.8.0.tar.gz";
hash = "sha256-PYm7QE6LDtTvMx8Nxi2HOFJjTKKoFK56Ssfv/BFDIM8=";
};
};
in
stdenv.mkDerivation {
pname = "bird";
version = "0.8.0";
src = fetchurl sources.${stdenv.hostPlatform.system};
dontConfigure = true;
dontBuild = true;
unpackPhase = ''
tar -xzf "$src"
'';
installPhase = ''
runHook preInstall
mkdir -p "$out/bin"
cp bird "$out/bin/bird"
chmod 0755 "$out/bin/bird"
runHook postInstall
'';
meta = with lib; {
description = "Fast X CLI for tweeting, replying, and reading";
homepage = "https://github.com/steipete/bird";
license = licenses.mit;
platforms = builtins.attrNames sources;
mainProgram = "bird";
};
}

View File

@ -1,37 +0,0 @@
{
lib,
stdenvNoCC,
fetchzip,
}:
stdenvNoCC.mkDerivation {
pname = "codexbar-app";
version = "0.23";
src = fetchzip {
url = "https://github.com/steipete/CodexBar/releases/download/v0.23/CodexBar-0.23.zip";
hash = "sha256-4LtZZzoP9tofNhy8jVkaopE+aivn0PRBEeJBGpDnbE8=";
stripRoot = false;
};
dontUnpack = true;
installPhase = ''
runHook preInstall
mkdir -p "$out/Applications"
app_path="$(find "$src" -maxdepth 2 -name 'CodexBar.app' -print -quit)"
if [ -z "$app_path" ]; then
echo "CodexBar.app not found in $src" >&2
exit 1
fi
cp -R "$app_path" "$out/Applications/CodexBar.app"
runHook postInstall
'';
meta = with lib; {
description = "CodexBar macOS menu bar app bundle";
homepage = "https://github.com/steipete/CodexBar";
license = licenses.mit;
platforms = [ "aarch64-darwin" ];
};
}

View File

@ -45,7 +45,7 @@ stdenv.mkDerivation {
meta = with lib; { meta = with lib; {
description = "Mirror Discord into SQLite and search server history locally"; description = "Mirror Discord into SQLite and search server history locally";
homepage = "https://github.com/steipete/discrawl"; homepage = "https://github.com/openclaw/discrawl";
license = licenses.mit; license = licenses.mit;
platforms = builtins.attrNames sources; platforms = builtins.attrNames sources;
mainProgram = "discrawl"; mainProgram = "discrawl";

View File

@ -39,7 +39,7 @@ stdenv.mkDerivation {
meta = with lib; { meta = with lib; {
description = "Google CLI for Gmail, Calendar, Drive, and Contacts"; description = "Google CLI for Gmail, Calendar, Drive, and Contacts";
homepage = "https://github.com/steipete/gogcli"; homepage = "https://github.com/openclaw/gogcli";
license = licenses.mit; license = licenses.mit;
platforms = builtins.attrNames sources; platforms = builtins.attrNames sources;
mainProgram = "gog"; mainProgram = "gog";

View File

@ -22,7 +22,7 @@ let
meta = with lib; { meta = with lib; {
description = "Modern Go client + CLI for the Google Places API (New)"; description = "Modern Go client + CLI for the Google Places API (New)";
homepage = "https://github.com/steipete/goplaces"; homepage = "https://github.com/openclaw/goplaces";
license = licenses.mit; license = licenses.mit;
platforms = builtins.attrNames sources; platforms = builtins.attrNames sources;
mainProgram = "goplaces"; mainProgram = "goplaces";

View File

@ -35,7 +35,7 @@ stdenv.mkDerivation {
meta = with lib; { meta = with lib; {
description = "Send and read iMessage / SMS from the terminal"; description = "Send and read iMessage / SMS from the terminal";
homepage = "https://github.com/steipete/imsg"; homepage = "https://github.com/openclaw/imsg";
license = licenses.mit; license = licenses.mit;
platforms = builtins.attrNames sources; platforms = builtins.attrNames sources;
mainProgram = "imsg"; mainProgram = "imsg";

View File

@ -31,7 +31,7 @@ stdenv.mkDerivation {
meta = with lib; { meta = with lib; {
description = "Lightning-fast macOS screenshots & AI vision analysis"; description = "Lightning-fast macOS screenshots & AI vision analysis";
homepage = "https://github.com/steipete/peekaboo"; homepage = "https://github.com/openclaw/Peekaboo";
license = licenses.mit; license = licenses.mit;
platforms = builtins.attrNames sources; platforms = builtins.attrNames sources;
mainProgram = "peekaboo"; mainProgram = "peekaboo";

View File

@ -1,38 +0,0 @@
{
description = "openclaw plugin: bird";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
};
outputs = { self, nixpkgs, root }:
let
lib = nixpkgs.lib;
systems = builtins.attrNames root.packages;
pluginFor = system:
let
packagesForSystem = root.packages.${system} or {};
bird = packagesForSystem.bird or null;
in
if bird == null then null else {
name = "bird";
skills = [ ./skills/bird ];
packages = [ bird ];
needs = {
stateDirs = [];
requiredEnv = [];
};
};
in {
packages = lib.genAttrs systems (system:
let
bird = (root.packages.${system} or {}).bird or null;
in
if bird == null then {}
else { bird = bird; }
);
openclawPlugin = pluginFor;
};
}

View File

@ -1,224 +0,0 @@
---
name: bird
description: X/Twitter CLI for reading, searching, posting, and engagement via cookies.
homepage: https://bird.fast
metadata:
{
"openclaw":
{
"emoji": "🐦",
"requires": { "bins": ["bird"] },
"install":
[
{
"id": "brew",
"kind": "brew",
"formula": "steipete/tap/bird",
"bins": ["bird"],
"label": "Install bird (brew)",
"os": ["darwin"],
},
{
"id": "npm",
"kind": "node",
"package": "@steipete/bird",
"bins": ["bird"],
"label": "Install bird (npm)",
},
],
},
}
---
# bird 🐦
Fast X/Twitter CLI using GraphQL + cookie auth.
## Install
```bash
# npm/pnpm/bun
npm install -g @steipete/bird
# Homebrew (macOS, prebuilt binary)
brew install steipete/tap/bird
# One-shot (no install)
bunx @steipete/bird whoami
```
## Authentication
`bird` uses cookie-based auth.
Use `--auth-token` / `--ct0` to pass cookies directly, or `--cookie-source` for browser cookies.
Run `bird check` to see which source is active. For Arc/Brave, use `--chrome-profile-dir <path>`.
## Commands
### Account & Auth
```bash
bird whoami # Show logged-in account
bird check # Show credential sources
bird query-ids --fresh # Refresh GraphQL query ID cache
```
### Reading Tweets
```bash
bird read <url-or-id> # Read a single tweet
bird <url-or-id> # Shorthand for read
bird thread <url-or-id> # Full conversation thread
bird replies <url-or-id> # List replies to a tweet
```
### Timelines
```bash
bird home # Home timeline (For You)
bird home --following # Following timeline
bird user-tweets @handle -n 20 # User's profile timeline
bird mentions # Tweets mentioning you
bird mentions --user @handle # Mentions of another user
```
### Search
```bash
bird search "query" -n 10
bird search "from:steipete" --all --max-pages 3
```
### News & Trending
```bash
bird news -n 10 # AI-curated from Explore tabs
bird news --ai-only # Filter to AI-curated only
bird news --sports # Sports tab
bird news --with-tweets # Include related tweets
bird trending # Alias for news
```
### Lists
```bash
bird lists # Your lists
bird lists --member-of # Lists you're a member of
bird list-timeline <id> -n 20 # Tweets from a list
```
### Bookmarks & Likes
```bash
bird bookmarks -n 10
bird bookmarks --folder-id <id> # Specific folder
bird bookmarks --include-parent # Include parent tweet
bird bookmarks --author-chain # Author's self-reply chain
bird bookmarks --full-chain-only # Full reply chain
bird unbookmark <url-or-id>
bird likes -n 10
```
### Social Graph
```bash
bird following -n 20 # Users you follow
bird followers -n 20 # Users following you
bird following --user <id> # Another user's following
bird about @handle # Account origin/location info
```
### Engagement Actions
```bash
bird follow @handle # Follow a user
bird unfollow @handle # Unfollow a user
```
### Posting
```bash
bird tweet "hello world"
bird reply <url-or-id> "nice thread!"
bird tweet "check this out" --media image.png --alt "description"
```
**⚠️ Posting risks**: Posting is more likely to be rate limited; if blocked, use the browser tool instead.
## Media Uploads
```bash
bird tweet "hi" --media img.png --alt "description"
bird tweet "pics" --media a.jpg --media b.jpg # Up to 4 images
bird tweet "video" --media clip.mp4 # Or 1 video
```
## Pagination
Commands supporting pagination: `replies`, `thread`, `search`, `bookmarks`, `likes`, `list-timeline`, `following`, `followers`, `user-tweets`
```bash
bird bookmarks --all # Fetch all pages
bird bookmarks --max-pages 3 # Limit pages
bird bookmarks --cursor <cursor> # Resume from cursor
bird replies <id> --all --delay 1000 # Delay between pages (ms)
```
## Output Options
```bash
--json # JSON output
--json-full # JSON with raw API response
--plain # No emoji, no color (script-friendly)
--no-emoji # Disable emoji
--no-color # Disable ANSI colors (or set NO_COLOR=1)
--quote-depth n # Max quoted tweet depth in JSON (default: 1)
```
## Global Options
```bash
--auth-token <token> # Set auth_token cookie
--ct0 <token> # Set ct0 cookie
--cookie-source <source> # Cookie source for browser cookies (repeatable)
--chrome-profile <name> # Chrome profile name
--chrome-profile-dir <path> # Chrome/Chromium profile dir or cookie DB path
--firefox-profile <name> # Firefox profile
--timeout <ms> # Request timeout
--cookie-timeout <ms> # Cookie extraction timeout
```
## Config File
`~/.config/bird/config.json5` (global) or `./.birdrc.json5` (project):
```json5
{
cookieSource: ["chrome"],
chromeProfileDir: "/path/to/Arc/Profile",
timeoutMs: 20000,
quoteDepth: 1,
}
```
Environment variables: `BIRD_TIMEOUT_MS`, `BIRD_COOKIE_TIMEOUT_MS`, `BIRD_QUOTE_DEPTH`
## Troubleshooting
### Query IDs stale (404 errors)
```bash
bird query-ids --fresh
```
### Cookie extraction fails
- Check browser is logged into X
- Try different `--cookie-source`
- For Arc/Brave: use `--chrome-profile-dir`
---
**TL;DR**: Read/search/engage with CLI. Post carefully or use browser. 🐦

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -1,7 +1,7 @@
--- ---
name: discrawl name: discrawl
description: Mirror Discord guild history into local SQLite and query it offline with search, messages, mentions, reports, and DM wiretap import. description: Mirror Discord guild history into local SQLite and query it offline with search, messages, mentions, reports, and DM wiretap import.
homepage: https://github.com/steipete/discrawl homepage: https://github.com/openclaw/discrawl
metadata: metadata:
{ {
"openclaw": "openclaw":

View File

@ -47,14 +47,14 @@
"lastModified": 1772109602, "lastModified": 1772109602,
"narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=", "narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "eddb00d4c1037a983913fccf32880aece050cd32", "rev": "eddb00d4c1037a983913fccf32880aece050cd32",
"type": "github" "type": "github"
}, },
"original": { "original": {
"narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=", "narHash": "sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "eddb00d4c1037a983913fccf32880aece050cd32", "rev": "eddb00d4c1037a983913fccf32880aece050cd32",
"type": "github" "type": "github"
} }

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=eddb00d4c1037a983913fccf32880aece050cd32&narHash=sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw="; root.url = "github:openclaw/nix-openclaw-tools?rev=eddb00d4c1037a983913fccf32880aece050cd32&narHash=sha256-Lzs6tzCkOOtDaZIRSGvS6ykJOtu0hZrdI95kxhkSIuw=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -47,14 +47,14 @@
"lastModified": 1770237944, "lastModified": 1770237944,
"narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=", "narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c", "rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=", "narHash": "sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c", "rev": "6352c8247b3b889d7f17bce1f09d6c58fd34932c",
"type": "github" "type": "github"
} }

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=6352c8247b3b889d7f17bce1f09d6c58fd34932c&narHash=sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0="; root.url = "github:openclaw/nix-openclaw-tools?rev=6352c8247b3b889d7f17bce1f09d6c58fd34932c&narHash=sha256-nfCSSyNU97XpKVPgo6mODBwrVeTOuMCl3i18QuGjpN0=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -1,8 +1,8 @@
--- ---
name: goplaces name: goplaces
description: Query Google Places API (New) via the goplaces CLI for text search, place details, resolve, and reviews. Use for human-friendly place lookup or JSON output for scripts. description: Query Google Places API (New) via the goplaces CLI for text search, place details, resolve, and reviews. Use for human-friendly place lookup or JSON output for scripts.
homepage: https://github.com/steipete/goplaces homepage: https://github.com/openclaw/goplaces
metadata: {"clawdbot":{"emoji":"📍","requires":{"bins":["goplaces"],"env":["GOOGLE_PLACES_API_KEY"]},"primaryEnv":"GOOGLE_PLACES_API_KEY","install":[{"id":"brew","kind":"brew","formula":"steipete/tap/goplaces","bins":["goplaces"],"label":"Install goplaces (brew)"}]}} metadata: {"openclaw":{"emoji":"📍","requires":{"bins":["goplaces"],"env":["GOOGLE_PLACES_API_KEY"]},"primaryEnv":"GOOGLE_PLACES_API_KEY","install":[{"id":"brew","kind":"brew","formula":"steipete/tap/goplaces","bins":["goplaces"],"label":"Install goplaces (brew)"}]}}
--- ---
# goplaces # goplaces

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }:

View File

@ -47,14 +47,14 @@
"lastModified": 1769797395, "lastModified": 1769797395,
"narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=", "narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9", "rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9",
"type": "github" "type": "github"
}, },
"original": { "original": {
"narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=", "narHash": "sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=",
"owner": "openclaw", "owner": "openclaw",
"repo": "nix-steipete-tools", "repo": "nix-openclaw-tools",
"rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9", "rev": "dbf0a31a57407d9140e32357ea8d0215bd9feed9",
"type": "github" "type": "github"
} }

View File

@ -3,7 +3,7 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D"; nixpkgs.url = "github:NixOS/nixpkgs?rev=16c7794d0a28b5a37904d55bcca36003b9109aaa&narHash=sha256-fFUnEYMla8b7UKjijLnMe%2BoVFOz6HjijGGNS1l7dYaQ%3D";
root.url = "github:openclaw/nix-steipete-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA="; root.url = "github:openclaw/nix-openclaw-tools?rev=dbf0a31a57407d9140e32357ea8d0215bd9feed9&narHash=sha256-QkPl/Rgk9DXgaVNhjvHHHjy5e81j+MzcVOouZRdUTLA=";
}; };
outputs = { self, nixpkgs, root }: outputs = { self, nixpkgs, root }: