bitfield/script
Making it easy to write shell-like scripts in Go
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 8mo ago
- ✓14 active contributors
- ✓MIT licensed
Show all 7 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 8mo ago
- ⚠Concentrated ownership — top contributor handles 79% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/bitfield/script)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/bitfield/script on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: bitfield/script
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/bitfield/script shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 8mo ago
- 14 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 8mo ago
- ⚠ Concentrated ownership — top contributor handles 79% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live bitfield/script
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/bitfield/script.
What it runs against: a local clone of bitfield/script — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in bitfield/script | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 263 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of bitfield/script. If you don't
# have one yet, run these first:
#
# git clone https://github.com/bitfield/script.git
# cd script
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of bitfield/script and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "bitfield/script(\\.git)?\\b" \\
&& ok "origin remote is bitfield/script" \\
|| miss "origin remote is not bitfield/script (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "script.go" \\
&& ok "script.go" \\
|| miss "missing critical file: script.go"
test -f "doc.go" \\
&& ok "doc.go" \\
|| miss "missing critical file: doc.go"
test -f "go.mod" \\
&& ok "go.mod" \\
|| miss "missing critical file: go.mod"
test -f "script_test.go" \\
&& ok "script_test.go" \\
|| miss "missing critical file: script_test.go"
test -f "README.md" \\
&& ok "README.md" \\
|| miss "missing critical file: README.md"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 263 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~233d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/bitfield/script"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
script is a Go library that brings shell script ergonomics to Go programs, enabling pipelines of operations on data streams (files, processes, stdin). It lets you chain operations like File().Match().CountLines() or Stdin().FilterLine().Stdout() with a fluent API inspired by Unix pipes, eliminating boilerplate for common sysadmin and data processing tasks. Simple, focused monolith: script.go is the core engine (~2000 LOC estimated) defining the Pipe type and all chainable methods. script_test.go contains unit tests; platform-specific behavior isolated in script_unix_test.go and script_windows_test.go. Testdata directory holds fixture files (logs, JSON, tar.zip) and txtar integration test scripts. No subdirectories—the entire public API lives in one package.
👥Who it's for
Go developers and DevOps engineers writing system administration tools, CLI utilities, and data processing scripts who want shell-script simplicity without dropping into bash. Users value clean piping syntax over explicit goroutines and channel wrangling.
🌱Maturity & risk
Production-ready and actively maintained. The project has comprehensive test coverage across Unix and Windows variants (script_test.go, script_unix_test.go, script_windows_test.go), dual CI workflows (audit.yml, ci.yml), and depends on stable, widely-trusted libraries (mvdan.cc/sh, itchyny/gojq). Latest activity and lack of major version instability suggest ongoing care.
Very low risk. Dependency footprint is minimal (5 direct deps, all well-maintained) with no recent critical CVEs. Single-maintainer repo (bitfield) is a known quantity in the Go community. No breaking changes visible in go.mod constraints (go 1.18 is reasonable). Primary risk is feature velocity: this is a focused, mature library, so don't expect rapid feature additions—it's stable by design.
Active areas of work
No active development signals visible in file structure (no CHANGELOG, no milestones listed). The library appears to be in a stable maintenance phase—well-tested, documented, and not expecting major features. Contribution focus is likely bug fixes and platform compatibility (note explicit Unix/Windows test split).
🚀Get running
git clone https://github.com/bitfield/script.git
cd script
go mod download
go test ./...
Daily commands:
No server/daemon. For dev iteration: go test ./... -v runs full test suite. go test ./... -run TestName runs specific tests. Single-file main.go examples would live outside this library (see README examples for usage patterns).
🗺️Map of the codebase
script.go— Core library implementation containing the Pipe type and all chainable methods that form the foundation of the pipeline architecture.doc.go— Package documentation defining the library's purpose, design philosophy, and usage patterns that every contributor must understand.go.mod— Dependency manifest showing critical external packages (gojq, mvdan.cc/sh) that power shell-like operations and query capabilities.script_test.go— Comprehensive test suite establishing expected behavior and serving as executable documentation for all pipeline operations.README.md— Primary entry point explaining library purpose, design rationale, and basic usage patterns for new contributors..github/workflows/ci.yml— Continuous integration configuration defining test, build, and quality gates that all PRs must pass.
🧩Components & responsibilities
- Pipe (pipeline orchestrator) (Go io.Reader interface, method chaining pattern) — Maintains internal Reader and error state; chains operations by wrapping Reader and composing transforms; materializes results on terminal call
- Failure mode: Silently accumulates error in internal state until Error() or String() called; first error stops pipeline but doesn't panic
- Exec (shell executor) (os/exec, mvdan.cc/sh parser, platform-specific process APIs) — Spawns subprocess, captures stdout, wraps result back into Pipe for further chaining
- Failure mode: Subprocess errors (exit code != 0) stored in Pipe state; non-zero exit does not stop chaining but will surface in final Error()
- Filter/Map/JQ (stream transformers) (bufio.Scanner, strings, gojq for JSON) — Read input line-by-line or bulk; apply predicate or transformation; write matching/transformed lines to output Reader
- Failure mode: Transformation errors (invalid regex, malformed JSON) stop processing and set Pipe error state
- Test suite (verification) (Go testing.T, google/go-cmp, txtar for shell script definitions) — Validates all operations across Unix/Windows platforms; uses test fixtures from testdata/
- Failure mode: Failed tests block CI/CD; audit workflow catches security vulnerabilities
🔀Data flow
File system (testdata/)→Pipe via File() or Exec()— Input data sourced from test fixtures or live file system; read into pipeline as io.ReaderPipe (previous operation output)→Pipe (next chained operation)— Each method wraps the previous Reader, composing transforms; data flows line-by-line or bulk through wrapped ReadersPipe internal Reader→String() or Error()— Terminal method reads entire remaining stream and materializes result as string or errorExec subprocess→Pipe Reader— Subprocess stdout captured and wrapped as io.Reader for downstream operationsFilter predicate (regex/lambda)→Output Reader— Matching or non-matching lines selected/dropped; gojq expressions evaluate JSON at runtime
🛠️How to make changes
Add a New Pipeline Operation Method
- Define the new method on the Pipe receiver in script.go, accepting operation-specific parameters (
script.go) - Implement the method to return *Pipe, applying your transformation logic to the internal data stream (
script.go) - Add comprehensive test cases in script_test.go covering normal cases, edge cases, and error conditions (
script_test.go) - If platform-specific, add OS-specific tests in script_unix_test.go or script_windows_test.go (
script_unix_test.go) - Add test fixtures to testdata/ directory if your operation needs sample input files (
testdata/)
Add Support for a New Shell Language Feature
- Identify the feature and check if mvdan.cc/sh already parses it; if extending shell compatibility, update Exec() in script.go (
script.go) - Add test cases in script_test.go demonstrating the new shell syntax working end-to-end (
script_test.go) - Add platform-specific tests if shell behavior differs between Unix and Windows (
script_unix_test.go)
Add a New Data Transformation Filter
- Implement as a new method on Pipe in script.go that reads input and applies line-by-line or bulk transformation logic (
script.go) - Leverage existing dependencies (gojq for queries, mvdan.cc/sh for shell patterns) if applicable (
script.go) - Add test fixtures in testdata/ (JSON, logs, or text files) representing inputs your filter will process (
testdata/) - Write comprehensive tests in script_test.go verifying correctness on various input types (
script_test.go)
🔧Why these technologies
- Go 1.18+ with generics-ready stdlib — Enables cross-platform system scripting with better performance and type safety than shell; method chaining mirrors familiar pipeline syntax
- mvdan.cc/sh/v3 (shell parser) — Parses and executes shell commands safely within Go process, allowing Exec() to handle complex shell pipelines and syntax
- itchyny/gojq (JSON query engine) — Provides jq-like JSON filtering and transformation capabilities without subprocess overhead
- google/go-cmp (diffing library) — Deep comparison for test assertions, making test failures readable and debuggable
⚖️Trade-offs already made
-
Stream-based pipeline architecture rather than loading entire files into memory
- Why: Allows processing of arbitrarily large files without memory explosion, matching shell script behavior
- Consequence: Operations must be composable and stateless; cannot easily look-ahead or require random access
-
Embed shell execution via subprocess (Exec) rather than pure Go reimplementation
- Why: Reuses existing shell semantics and tool ecosystem; simpler than reimplementing shell in Go
- Consequence: Cross-platform differences require platform-specific test suites; subprocess overhead for very small operations
-
Method chaining (fluent API) for pipeline construction
- Why: Mirrors familiar shell syntax (cmd | filter | transform) and is intuitive for sequential transformations
- Consequence: All methods return *Pipe, making it impossible to handle errors mid-pipeline without explicit checking; requires terminal method (.String(), .Error()) to materialize result
-
No explicit buffering or batching layer; lines processed one-at-a-time
- Why: Simplicity and predictability; easier to reason about memory usage and control flow
- Consequence: Some operations (sorting, grouping) cannot be done efficiently without breaking the pipeline abstraction
🚫Non-goals (don't propose these)
- Real-time streaming or event-driven I/O (blocking operations only)
- Complex shell features like job control, process groups, or signal handling
- Full POSIX shell compatibility (uses mvdan.cc/sh subset)
- Distributed or parallel execution across machines
⚠️Anti-patterns to avoid
- Silent error accumulation —
script.go (Pipe.err field and all methods): Errors are silently stored in Pipe.err and only surface when Error() or String() is called; intermediate operations don't short-circuit, making debugging harder if
🪤Traps & gotchas
None obvious. Behavior is deterministic across platforms via explicit Unix/Windows test branching. No hidden env vars, no external service dependencies. One subtle point: shell metacharacters in arguments passed to Exec() are handled by mvdan.cc/sh—ensure quoting matches your intent (see testdata/script/*.txtar for examples).
🏗️Architecture
💡Concepts to learn
- Unix Pipes and Streams — script.go's entire design philosophy mirrors Unix pipes—understanding how data flows through stdin/stdout/stderr and how programs compose via readers/writers is essential to using the API idiomatically
- Fluent Interface / Method Chaining — The Pipe type returns itself from every method, enabling the ergonomic File().Match().CountLines() syntax; recognizing this pattern helps predict API behavior and extend it
- io.Reader Interface — Pipe wraps an io.Reader and passes it through transformations; understanding this fundamental Go interface lets you hook in custom readers or integrate with other libraries
- Shell Metacharacter Escaping — Exec() uses mvdan.cc/sh to parse shell syntax safely; knowing how quoting and escaping work (single vs. double quotes, $-expansion) prevents injection bugs
- jq Query Language — The JQ() method applies jq transformations to JSON streams; familiarity with jq syntax (path expressions, filters, pipes) is required to use this effectively
- Go Context Timeout and Cancellation — Although not visible in the file structure, Exec() integrates with context.Context for subprocess lifecycle; understanding context is crucial for production scripts that need timeout/cancellation
- Cross-Platform File Path Handling — The Unix/Windows test split shows that filepath.Separator, path escaping, and process quoting differ—writing portable scripts requires attention to platform-specific behavior
🔗Related repos
mvdan/sh— Direct dependency (mvdan.cc/sh) for shell lexing and parsing; used by script.Exec() to safely interpret shell commandsitchyny/gojq— Direct dependency for JQ() method; provides jq-compatible JSON querying within Go pipelinesgoogle/go-cmp— Testing dependency used in script_test.go for deep equality assertions; required for verifying complex outputgolang/go— Core runtime; script.go relies heavily on io.Reader/Writer composition and os/exec patterns from stdlibbitfield/testing— Companion testing utilities by the same author (bitfield) for assertions and test helpers in Go; often paired with script for integration test suites
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive Windows-specific pipe and stream handling tests in script_windows_test.go
The repo has script_unix_test.go with platform-specific tests, but script_windows_test.go likely has minimal coverage. Windows handles pipes, stdin/stdout, and process termination differently than Unix. Given the testdata/script/*.txtar files exist for testing argument and stdin piping, these scenarios should be explicitly validated on Windows to prevent cross-platform regressions.
- [ ] Review existing testdata/script/args_sends_arguments_to_pipe.txtar and testdata/script/stdin_sends_stdin_to_pipe.txtar test cases
- [ ] Add Windows-specific tests in script_windows_test.go covering: pipe buffering behavior, line ending handling (CRLF vs LF), subprocess signal handling on Windows, and output stream ordering under concurrent operations
- [ ] Ensure tests validate that script.go's pipe implementations handle Windows limitations around process cleanup and I/O redirection
Add integration tests using txtar format for complex piping scenarios in testdata/script/
The repo has script/args_sends_arguments_to_pipe.txtar and script/stdin_sends_stdin_to_pipe.txtar, suggesting txtar-based integration tests exist. However, critical piping scenarios are missing: (1) error propagation through multi-stage pipes, (2) handling of binary data in pipes, (3) large file streaming, and (4) concurrent read/write operations. These should be added as txtar files and tested with the go-internal/txtar testing framework already in dependencies.
- [ ] Create testdata/script/error_propagation_through_pipes.txtar testing failure handling across multiple pipe stages
- [ ] Create testdata/script/large_file_streaming.txtar validating memory efficiency with multi-GB files
- [ ] Create testdata/script/concurrent_pipe_operations.txtar for race condition detection
- [ ] Add corresponding test cases in script_test.go that load and execute these txtar scenarios
Add GitHub Action workflow for testing against multiple Go versions (1.18+) in .github/workflows/
The repo specifies go 1.18 as minimum, but ci.yml likely tests only the latest or a single version. The go-cmp, gojq, and sh/v3 dependencies may have compatibility issues across Go 1.18, 1.19, 1.20, 1.21+. A matrix workflow would catch version-specific regressions early and signal compatibility guarantees to users.
- [ ] Create .github/workflows/test-versions.yml with a matrix strategy for go-version: ['1.18', '1.19', '1.20', '1.21', 'latest']
- [ ] Run 'go test ./...' and 'go vet ./...' for each version
- [ ] Ensure testdata files and platform-specific tests (script_unix_test.go, script_windows_test.go) execute in the matrix across linux, windows, and macos runners
🌿Good first issues
- Add a
Reverse()method that reverses line order in the pipeline—requires implementing a buffering strategy in script.go and adding tests in script_test.go - Document and test the jq integration more thoroughly—testdata/ lacks .json examples for JQ() method; add fixture files and integration tests in script_test.go
- Extend Windows tests (script_windows_test.go) to cover edge cases like UNC paths (\server\share) and PowerShell-specific quoting in Exec()
⭐Top contributors
Click to expand
Top contributors
- @bitfield — 79 commits
- @mahadzaryab1 — 7 commits
- @thiagonache — 2 commits
- @thomaspoignant — 2 commits
- @tho — 1 commits
📝Recent commits
Click to expand
Recent commits
646fe23— add links to readme (#234) (bitfield)6006cd0— update changelog (#228) (bitfield)348e77b— Change JQ to process newline-delimited JSON (#227) (tho)5b2f8f4— Add go-script to readme (#222) (bitfield)50f0076— Tools (#220) (bitfield)29d5eb2— update readme (#219) (bitfield)bf66ef5— Make FindFiles ignore (trivial) errors (#217) (mahadzaryab1)dd8d444— Slice now produces empty pipe for empty slice (fixes #110) (#216) (mahadzaryab1)6fff62a— AddHash/HashSums(#215) (mahadzaryab1)0296fd2— release v0.23 (bitfield)
🔒Security observations
The bitfield/script project has a generally acceptable security posture for a shell scripting library, but has several outdated dependencies that should be updated immediately. The primary concern is that Go 1.18 is end-of-life and golang.org/x/sys v0.10.0 is significantly outdated. While the library itself appears to follow good practices based on the file structure (includes tests, CI/CD automation), users must be cautious about command injection risks when using this library with untrusted input. No hardcoded secrets, exposed credentials, or major architectural security issues were detected. Updating dependencies and adding a security policy would improve the overall security posture.
- High · Outdated Go Version —
go.mod. The project targets Go 1.18, which reached end-of-life in September 2023. Using outdated Go versions exposes the project to known security vulnerabilities and missing security patches in the standard library. Fix: Update go.mod to target Go 1.21 or later (preferably 1.22+). Review and test compatibility with the newer version. - High · Vulnerable Dependency: golang.org/x/sys —
go.mod (indirect dependency). The dependency golang.org/x/sys v0.10.0 (from August 2023) is outdated. This package contains system-level APIs and may have unpatched security vulnerabilities. Fix: Update golang.org/x/sys to v0.17.0 or later. Run 'go get -u golang.org/x/sys' and verify tests pass. - Medium · Vulnerable Dependency: golang.org/x/tools —
go.mod (indirect dependency). The dependency golang.org/x/tools v0.11.0 (from August 2023) is outdated. While primarily a development tool, it may contain security issues affecting code analysis. Fix: Update golang.org/x/tools to v0.17.0 or later to receive security patches and improvements. - Medium · Potential Command Injection via Shell Execution —
script.go (core library functionality). This library (script) is designed to execute shell commands and subprocesses. While the library itself may be well-designed, applications using it must be extremely careful about passing untrusted input to shell execution functions, as this could lead to command injection vulnerabilities. Fix: Document command injection risks clearly in the README and examples. Recommend users validate and sanitize all inputs before passing to shell execution methods. Consider providing safe alternatives that avoid shell interpretation. - Low · Missing Security Policy —
Repository root. The repository does not contain a SECURITY.md file, which should outline the project's vulnerability disclosure policy and security contact information. Fix: Create a SECURITY.md file following GitHub's recommended format (https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository) with responsible disclosure guidelines. - Low · No Dependency Pinning in CI/CD —
.github/workflows/audit.yml. The audit.yml workflow may not be pinning dependency versions, which could lead to transitive dependency changes causing unexpected behavior. Fix: Ensure go.sum is committed and CI/CD workflows run 'go mod verify' to detect unexpected changes. Consider using 'go mod tidy' in CI to ensure consistency.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.