RepoPilotOpen in app →

jpillora/cloud-torrent

☁️ Cloud Torrent: a self-hosted remote torrent client

Mixed

Slowing — last commit 5mo ago

weakest axis
Use as dependencyConcerns

copyleft license (AGPL-3.0) — review compatibility; no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 5mo ago
  • 7 active contributors
  • AGPL-3.0 licensed
Show all 8 evidence items →
  • CI configured
  • Slowing — last commit 5mo ago
  • Single-maintainer risk — top contributor 88% of recent commits
  • AGPL-3.0 is copyleft — check downstream compatibility
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

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 "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/jpillora/cloud-torrent?axis=fork)](https://repopilot.app/r/jpillora/cloud-torrent)

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/jpillora/cloud-torrent on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: jpillora/cloud-torrent

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:

  1. 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.
  2. 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.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/jpillora/cloud-torrent 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

WAIT — Slowing — last commit 5mo ago

  • Last commit 5mo ago
  • 7 active contributors
  • AGPL-3.0 licensed
  • CI configured
  • ⚠ Slowing — last commit 5mo ago
  • ⚠ Single-maintainer risk — top contributor 88% of recent commits
  • ⚠ AGPL-3.0 is copyleft — check downstream compatibility
  • ⚠ No test directory detected

<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 jpillora/cloud-torrent repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/jpillora/cloud-torrent.

What it runs against: a local clone of jpillora/cloud-torrent — 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 jpillora/cloud-torrent | Confirms the artifact applies here, not a fork | | 2 | License is still AGPL-3.0 | 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 ≤ 190 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>jpillora/cloud-torrent</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of jpillora/cloud-torrent. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/jpillora/cloud-torrent.git
#   cd cloud-torrent
#
# 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 jpillora/cloud-torrent and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "jpillora/cloud-torrent(\\.git)?\\b" \\
  && ok "origin remote is jpillora/cloud-torrent" \\
  || miss "origin remote is not jpillora/cloud-torrent (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is AGPL-3.0" \\
  || miss "license drift — was AGPL-3.0 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 "main.go" \\
  && ok "main.go" \\
  || miss "missing critical file: main.go"
test -f "engine/engine.go" \\
  && ok "engine/engine.go" \\
  || miss "missing critical file: engine/engine.go"
test -f "server/server.go" \\
  && ok "server/server.go" \\
  || miss "missing critical file: server/server.go"
test -f "server/server_api.go" \\
  && ok "server/server_api.go" \\
  || miss "missing critical file: server/server_api.go"
test -f "static/files/js/run.js" \\
  && ok "static/files/js/run.js" \\
  || miss "missing critical file: static/files/js/run.js"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 190 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~160d)"
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/jpillora/cloud-torrent"
  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).

</details>

TL;DR

Cloud Torrent is a self-hosted remote torrent client written in Go that runs as a single binary, allowing users to start and manage torrent downloads on a server and stream/retrieve completed files via HTTP. It embeds torrent search, provides real-time WebSocket updates via the velox library, and serves files efficiently using Go's native http.ServeContent. Monolithic Go binary: engine/ contains the torrent engine logic (config.go, engine.go, torrent.go), server/ handles HTTP routing and REST APIs (server.go, server_api.go, server_files.go, server_search.go, server_stats.go), and static/ embeds the AngularJS frontend (HTML, CSS, JavaScript controllers). main.go orchestrates startup with opts-based CLI flag parsing.

👥Who it's for

System administrators and privacy-conscious users who want to run a personal torrent client on a VPS or home server without relying on third-party services. Developers deploying self-hosted infrastructure who need a lightweight, containerized torrent solution.

🌱Maturity & risk

Actively maintained with official Docker images, CI/CD via GitHub Actions (ci.yml), and goreleaser-based binary releases. The project has a polished README with deployment guides for DO/Vultr/AWS, suggesting production readiness. However, test coverage is not evident from the file structure, and the single-digit contributor pattern suggests moderate maturity rather than high velocity.

Depends on anacrolix/torrent (a third-party DHT/BitTorrent library) and jpillora's collection of small utility libraries (opts, velox, cookieauth, scraper) which are maintained by a single author and have not been audited extensively. The repo itself shows no visible test files in the file structure. Long-term maintenance risk stems from jpillora's single-maintainer pattern across multiple dependencies.

Active areas of work

No specific PR or branch data is visible in the file structure provided. The presence of go 1.25.4 in go.mod and recent dependency versions (anacrolix/torrent 1.59.1, gopsutil/v3 3.24.5) suggest active maintenance. The GitHub Actions ci.yml and goreleaser.yml indicate automated builds are configured.

🚀Get running

git clone https://github.com/jpillora/cloud-torrent.git
cd cloud-torrent
go build -o cloud-torrent .
./cloud-torrent --help
./cloud-torrent --port 3000

Then visit http://localhost:3000. Alternatively, use the Docker image: docker run -d -p 3000:3000 -v /path/to/downloads:/downloads jpillora/cloud-torrent.

Daily commands:

go run main.go
# Runs on http://localhost:3000 by default
# Or build then execute:
go build -o cloud-torrent .
./cloud-torrent --port 3000 --title 'My Cloud Torrent'

For Docker: docker run -d -p 3000:3000 -v /downloads:/downloads jpillora/cloud-torrent.

🗺️Map of the codebase

  • main.go — Application entry point and startup configuration; every contributor must understand how the app initializes and command-line flags are parsed.
  • engine/engine.go — Core torrent engine implementation managing the torrent client lifecycle; essential to understand how torrents are added, downloaded, and tracked.
  • server/server.go — HTTP server and request routing; every backend change flows through this router and middleware setup.
  • server/server_api.go — REST API endpoints for torrent operations (add, remove, pause, resume); critical for understanding how frontend commands reach the engine.
  • static/files/js/run.js — Frontend AngularJS application entry point and controller wiring; essential for understanding UI data binding and API call orchestration.
  • engine/torrent.go — Torrent model and state management; contributors need to understand how individual torrent data is structured and mutated.
  • static/static.go — Embedded static asset serving configuration; demonstrates how frontend assets are bundled and served by the Go binary.

🛠️How to make changes

Add a new API endpoint

  1. Create the handler function in server_api.go (or a new server_*.go file if domain-specific), taking http.ResponseWriter and *http.Request (server/server_api.go)
  2. Register the route in server/server.go using mux.HandleFunc("/api/path", handler) within the setupRoutes function (server/server.go)
  3. Call the endpoint from the frontend controller (e.g., torrents-controller.js) using $http.post or $http.get with appropriate error handling (static/files/js/torrents-controller.js)
  4. Update the UI template to add buttons or triggers that invoke the API call (static/files/template/torrents.html)

Add a new UI view/controller

  1. Create a new AngularJS controller file in static/files/js/your-feature-controller.js with $scope variables and API calls (static/files/js/torrents-controller.js)
  2. Create the HTML template in static/files/template/your-feature.html with ng-repeat, ng-click, and form bindings (static/files/template/torrents.html)
  3. Register the route and controller in static/files/js/run.js using $routeProvider.when() and $stateProvider (or similar) (static/files/js/run.js)
  4. Add a navigation link in static/files/index.html to navigate to the new view (static/files/index.html)

Add a new torrent engine feature

  1. Extend the Torrent or Engine struct in engine/torrent.go or engine/engine.go with new fields and getter methods (engine/torrent.go)
  2. Implement business logic in engine/engine.go methods (e.g., AddTorrent, GetStats) to interact with the anacrolix/torrent client (engine/engine.go)
  3. Expose the feature via a new API endpoint in server/server_api.go that calls your engine method and returns JSON (server/server_api.go)
  4. Call the endpoint from the frontend controller and update UI state accordingly (static/files/js/torrents-controller.js)

🔧Why these technologies

  • Go + anacrolix/torrent — Cross-platform, single binary, efficient concurrent I/O for managing multiple torrent downloads and HTTP serving simultaneously.
  • AngularJS (1.x) frontend — Lightweight real-time two-way data binding for live torrent progress updates without page refreshes; easy to embed in static assets.
  • Embedded static assets (static.go) — Enables single-binary distribution—no external dependencies or configuration files required; simplifies deployment.
  • HTTP for file serving (ServeContent) — Go's net/http.ServeContent provides resume support, range requests, and efficient streaming for large files out of the box.
  • JSON REST API — Stateless, cacheable API design; decouples frontend from backend; enables future mobile or CLI clients.

⚖️Trade-offs already made

  • AngularJS (v1) instead of modern framework (React, Vue)

    • Why: Smaller bundle size, easy to embed, and sufficient for the single-page-app use case at the time of creation.
    • Consequence: Limited IDE support, digest cycle performance concerns at scale, but acceptable for a self-hosted app with typically <100 torrents.
  • Polling/streaming stats instead of persistent WebSocket

    • Why: Simpler to implement; fewer connection state issues across firewalls and proxies.
    • Consequence: Slight latency in progress updates and higher server polling load on busy instances; mitigated by short intervals and caching.
  • Embedded configuration and no database

    • Why: Reduces operational complexity; config stored in memory or file-based; suitable for single-instance self-hosted use.
    • Consequence: No multi-instance synchronization or persistent metadata; loss of state on restart (torrents resume from disk but UI state resets).
  • File serving directly from local disk

    • Why: Minimal overhead; leverage kernel-level sendfile for efficiency; direct filesystem semantics.
    • Consequence: No deduplication, encryption at rest, or distributed storage; assumes local disk reliability.

🚫Non-goals (don't propose these)

  • Does not handle user authentication or multi-user isolation (relies on network isolation or reverse proxy auth).
  • Does not support multi-instance clustering or distributed torrent state.
  • Does not implement encrypted transport (TLS/SSL) natively—expected to be handled by reverse proxy.
  • Does not persist torrent metadata or history across restarts—torrents must be re-added.
  • Does not provide a native mobile application (mobile-friendly UI only).

🪤Traps & gotchas

No visible test files: There are no *_test.go files in the provided file structure, so test coverage is unclear. Velox WebSocket requirement: Real-time updates depend on jpillora/velox; if the frontend loses connection, updates may buffer or stall. Single downloads directory: The app assumes /downloads (or a single mounted volume) exists; multi-path downloads are not visible in the config. Anacrolix torrent quirks: The torrent library may require specific DHT/UPnP configuration; check anacrolix/torrent docs if peers aren't found. AngularJS legacy: The frontend uses AngularJS (1.x era), not modern Angular; DOM selectors and two-way binding patterns may surprise modern frontend developers.

🏗️Architecture

💡Concepts to learn

  • BitTorrent DHT (Distributed Hash Table) — Cloud Torrent uses anacrolix/torrent which implements DHT for peer discovery without trackers; understanding DHT is essential to debug why torrents aren't finding peers or magnet links fail
  • Magnet Links — The app supports magnet-based torrent addition via /api/torrents; knowing the magnet URI scheme (xt, dn, tr parameters) helps troubleshoot why certain links don't work
  • WebSocket (via jpillora/velox) — Real-time frontend updates (torrent progress, file availability) are pushed via WebSocket; understanding the velox protocol helps debug UI lag or missed updates
  • HTTP Range Requests and Streaming — File serving uses Go's http.ServeContent which implements HTTP 206 Range requests for efficient video streaming and resumable downloads; critical for large file handling
  • AngularJS Two-Way Data Binding — The frontend relies on AngularJS 1.x controllers with $scope and ng-model; understanding digest cycles and controller inheritance is needed to modify the UI without breaking updates
  • Single-Page Application (SPA) Architecture — Cloud Torrent's frontend is an SPA with multiple AngularJS controllers (torrents, downloads, omni, config) sharing state; routing and controller lifecycle patterns differ from server-rendered apps
  • Go Goroutines and Channels — The engine likely uses goroutines for concurrent torrent management and channel-based communication; proficiency with Go concurrency patterns is essential to understand engine.go and avoid race conditions
  • transmission/transmission — Mature, multi-platform torrent client with remote web interface; direct architectural competitor with more features but higher complexity
  • qbittorrent/qBittorrent — Feature-rich torrent client with web UI and API; heavier than Cloud Torrent but battle-tested in production for power users
  • Deluge/deluge — Python-based torrent client with plugin system and web console; alternative self-hosted solution with different deployment model
  • anacrolix/torrent — The Go BitTorrent library that powers Cloud Torrent's core torrent protocol implementation; understand this to debug protocol issues
  • jpillora/velox — Real-time update library used by Cloud Torrent for WebSocket push updates to the frontend; modify if you need different real-time patterns

🪄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 integration tests for server API endpoints (server/server_api.go)

The repo has comprehensive API endpoints for torrent management (server_api.go, server_files.go, server_search.go, server_stats.go) but no visible test files. Adding integration tests would ensure the API contracts remain stable, improve reliability for contributors, and serve as living documentation of expected behavior. This is particularly important for a networked service where subtle bugs can cause data loss.

  • [ ] Create server/server_api_test.go with tests for torrent add/remove/pause/resume endpoints
  • [ ] Create server/server_files_test.go with tests for file listing and download endpoints
  • [ ] Create server/server_search_test.go with tests for search functionality
  • [ ] Add test fixtures or mock torrent data in a testdata/ directory
  • [ ] Update CI workflow (.github/workflows/ci.yml) to run go test ./... on all packages

Add missing engine unit tests for torrent lifecycle (engine/torrent.go, engine/engine.go)

The engine package handles critical torrent operations (downloading, seeding, cleanup) but has no visible test coverage. Unit tests for the torrent state machine (adding, starting, stopping, removing torrents) would catch regressions early and make the codebase more maintainable. The config.go file suggests configuration complexity that also needs testing.

  • [ ] Create engine/engine_test.go with tests for Engine initialization and configuration
  • [ ] Create engine/torrent_test.go with tests for torrent add/start/stop/remove operations
  • [ ] Create engine/config_test.go with tests for configuration parsing and validation
  • [ ] Mock the anacrolix/torrent dependency to avoid network calls in tests
  • [ ] Ensure tests cover error cases (invalid magnet links, corrupted config, etc.)

Document and add tests for static file embedding (static/static.go)

The static.go file handles embedding of the web UI assets (HTML, CSS, JS in static/files/), but there's no documentation or tests for this critical path. A new contributor won't understand how the web UI is bundled, and there's no validation that all assets are properly embedded. This is a common source of deployment bugs where assets silently fail to load.

  • [ ] Add comments in static/static.go explaining the embedding mechanism and how to rebuild after asset changes
  • [ ] Create static/static_test.go with tests verifying all HTML templates in static/files/template/ are accessible
  • [ ] Add test to verify CSS and JS files (semantic.min.css, angular.min.js, etc.) are properly embedded
  • [ ] Add test for the font files in static/files/css/Lato/ and icon fonts in themes/default/assets/fonts/
  • [ ] Document in CONTRIBUTING.md how to update static assets and rebuild the binary

🌿Good first issues

  • Add integration tests for server_api.go endpoints: Write Go test cases covering /api/torrents (list), /api/torrents/add (POST), /api/torrents/:id/resume, /api/torrents/:id/pause. This will validate the REST API contract and catch regressions.: The absence of visible *_test.go files means core API logic is untested; a contributor can add high-value test coverage with minimal architectural changes.
  • Document the frontend architecture in CONTRIBUTING.md: Explain how the AngularJS controllers (torrents-controller.js, downloads-controller.js, etc.) communicate with the backend via /api/, how velox WebSocket updates are handled, and what each controller's scope model contains. Add a state diagram or flow chart.: Frontend onboarding is painful without docs on the AngularJS-to-Go integration pattern; new contributors struggle to wire features end-to-end.
  • Add missing error handling and recovery in server/server_files.go: Implement graceful degradation when a file is deleted while being streamed, add Content-Security-Policy headers, and validate file paths to prevent directory traversal. Write unit tests for edge cases.: File serving is a security-critical path; current implementation (inferred from file name alone) likely lacks defensive checks that a production deployment needs.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • fa0d095 — bump deps (jpillora)
  • c931df6 — bump goreleaser config to v2 (jpillora)
  • a24f28d — update goreleaser (jpillora)
  • eff6eb8 — and tidy (jpillora)
  • 31b3886 — bump go and deps (jpillora)
  • 61c4d76 — fix version string (jpillora)
  • 1133cbd — docs (jpillora)
  • b8ed88c — progress (jpillora)
  • 06f454c — compiles but torrent needs updating (jpillora)
  • 50a5ad5 — wip (jpillora)

🔒Security observations

  • High · Outdated Go Version — go.mod. The project specifies 'go 1.25.4' in go.mod, which appears to be a future/invalid version. Go's latest stable version is 1.21.x. This could indicate misconfiguration or use of untested/unsupported Go runtime, potentially missing critical security patches. Fix: Update to the latest stable Go version (1.21.x or 1.22.x) and test thoroughly. Verify the actual Go version being used in CI/CD and Docker builds.
  • High · Outdated Torrent Library — go.mod - github.com/anacrolix/torrent v1.59.1. The anacrolix/torrent dependency (v1.59.1) may contain known vulnerabilities. Torrent libraries are complex and often have security implications related to peer validation, protocol handling, and resource exhaustion. Fix: Run 'go list -u -m all' to check for updates. Audit anacrolix/torrent for known CVEs. Consider implementing rate limiting and peer validation.
  • High · Missing Authentication/Authorization in API — server/server_api.go, server/server_files.go, server/server_search.go. The codebase contains server API endpoints (server/server_api.go, server/server_files.go, server/server_search.go) that handle file access and torrent operations. While cookieauth is imported, there's no evidence of proper authentication/authorization enforcement across all sensitive endpoints, potentially allowing unauthorized access to downloaded files and torrent controls. Fix: Implement mandatory authentication for all API endpoints. Validate user permissions before serving files or accepting torrent commands. Use the cookieauth library consistently across all handlers.
  • High · Potential Path Traversal in File Server — server/server_files.go. The file serving functionality (server/server_files.go) may be vulnerable to path traversal attacks if user input is not properly sanitized when serving downloaded torrents. An attacker could potentially access files outside the intended download directory. Fix: Implement strict path validation using filepath.Clean() and verify all paths are within the designated download directory. Use filepath.EvalSymlinks() to prevent symlink-based attacks.
  • High · No HTTPS/TLS Configuration Visible — server/server.go, main.go. The application appears to serve HTTP without mandatory HTTPS. For a remote torrent client handling file downloads and potentially sensitive operations, lack of encryption in transit is a significant security risk. Fix: Implement HTTPS/TLS support. Generate or accept certificates. Redirect HTTP to HTTPS. Consider HSTS headers for additional security.
  • Medium · Potential XSS Vulnerabilities in Frontend — static/files/template/*.html, static/files/js/*-controller.js. Angular.js templates are used (static/files/js/vendor/angular.min.js with controllers in static/files/js/). If torrent names, file names, or search results are rendered without proper escaping, XSS attacks are possible. Fix: Ensure all dynamic content is properly escaped using Angular's sanitization. Use ngBind or {{}}, avoid ng-bind-html without sanitization. Implement Content Security Policy (CSP) headers.
  • Medium · No Rate Limiting on Search/API Endpoints — server/server_search.go. The embedded torrent search functionality (server/server_search.go) lacks visible rate limiting, which could allow attackers to abuse the search API or DoS the service through excessive queries. Fix: Implement rate limiting per IP/user. Use middleware to enforce query limits. Consider implementing CAPTCHA for search functionality.
  • Medium · Potential Command Injection via Archive Operations — engine/engine.go (likely uses archive). The archive library (github.com/jpillora/archive) is imported and likely used for file extraction. Archive operations can be vulnerable to zip bombs, path traversal, or command injection if not properly validated. Fix: Validate archive contents before extraction. Set limits on decompression ratios and file counts. Avoid shell execution for archive operations. Sanitize filenames extracted from archives.
  • Medium · — undefined. undefined Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · jpillora/cloud-torrent — RepoPilot