Ship code without wiring together five services.

← Back to NTJ Labs
Internal Technology
// built inside NTJ · v0.4 · feature/oauth
devloop@prod ~ /workspace/orders-svc · branch: main · v2.4.1
whoami
Ship code without wiring together five services.
describe
Repos, branches, PRs, CI/CD, deploys — in one place, running on
your infrastructure. Not GitHub + Vercel + Sentry + a dozen
webhooks trying to talk to each other.
demo
+──────────────────────────────────────────────────+ │ built for terminals · runs in the browser · ok │ +──────────────────────────────────────────────────+
deploy.log · main · live
streaming · events: 0 · uptime: 99.98% · host: hetzner · eu
// $ ls ./features

What it does (no fluff)

Six modules. Each one is something a dev team actually needs daily. No buzzword soup. Just tools that work.

01

~/repos

All your repositories — one view. Branches, tags, releases.

24 repos indexed · last sync 12s ago
02

~/branches

Compare, merge, delete. With a kanban view if you want it.

3 stale branches (>30d) — prune?
03

~/commits

Search, blame, revert. Author avatars and timestamps.

i 12,847 commits indexed · search < 80ms
04

~/pull-requests

Diff viewer with inline comments. Approvals. Merges.

8 open · 14 awaiting review · 2 conflicting
05

~/ci-cd

Triggers on commit. Status across all repos. Pipeline history.

last 50 builds: 48 pass / 2 flake
06

~/tasks

Kanban that syncs with git activity. Tasks linked to commits.

i auto-linked: 94% · stale tickets: 7
// how it sees a deploy

From commit to verified in 5 steps

Every step is observable. Every failure is recoverable. You don't need to ssh into a box at 2am to figure out what happened.

”Œ”€”€”€”€” │ Œ¥ │ │git │ └────┘
[1/5]
commit
webhook fires
devloop ingests
”Œ”€”€”€”€” │ š™ │ │ CI │ └────┘
[2/5]
CI runs
lint · test · build
parallel where it can
”Œ”€”€”€”€” │ œŽ │ │ PR │ └────┘
[3/5]
review
diff · comments
approvals · merge
”Œ”€”€”€”€” │ ▶ │ │ DEP│ └────┘
[4/5]
deploy
staging → prod
blue/green if set
”Œ”€”€”€”€” │ œ“ │ │ OK │ └────┘
[5/5]
verify
smoke tests
health probes
Every step is observable. · Every failure is recoverable.
// $ tail -f /var/log/devloop

Live deploy log & commit graph

This isn't a screenshot. The log on the left streams. The graph on the right is rendered from a real repo shape. Nothing is fake about the activity feel.

Sample data — illustrative only
tail -f deploy.log · orders-svc · main
git log --graph --oneline --all · last 14 commits
a3f9c12 fix(api): retry on 502 with backoff tom b8e4d72 feat(auth): wire up OAuth callback noa c1a7e83 test(auth): cover refresh-token path noa d2b1f04 hotfix: null check on session.user ari e9c2a15 refactor: extract token service noa f4d8b26 chore(deps): bump pg to 8.11.5 tom 07e3c41 release: v2.4.0-rc.1 ci-bot 18a5d92 docs(readme): add deploy section noa 2c9b657 fix(worker): handle SIGTERM cleanly tom 3e1f078 release: v2.4.0 ci-bot 4d8e389 hotfix: cap retry budget at 3 ari 5a2c490 perf(orders): cache by (uid, day) noa 6f5d8a1 release: v2.4.1 ci-bot 7e8a912 Merge tag 'v2.4.1' into main tom 8b1f7a3 chore: changelog for 2.4.1 tom HEAD → main branches: main feat/oauth release/2.4 hotfix
● CI: passing · 124 builds this week · 96% pass rate · last deploy: 14m ago · mean build: 4m 32s · p95 deploy: 2m 18s · flaky test rate: 0.8%
// $ man devloop

Things DevLoop actually does

Three of the screens you'll be staring at the most. Nothing here is a marketing rendering — these are the real UIs.

Diff viewer that doesn't suck

go · pkg/orders/handler.go · +14 / -8
pkg/orders/handler.go PR #284 · + approved by ari
4242func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) {
4343 ctx := r.Context()
44 body, err := io.ReadAll(r.Body)
45 if err != nil {
46 http.Error(w, "bad body", 400)
47 return
48 }
44 var req CreateOrderReq
45 if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
46 h.logger.Warn(ctx, "invalid request", "err", err)
47 respondErr(w, http.StatusBadRequest, ErrBadRequest)
48 return
49 }
50 // trace boundary for distributed retries
51 ctx = trace.WithSpan(ctx, "orders.create")
4952 order, err := h.svc.Create(ctx, req)
5053 if err != nil { respondErr(w, 500, err); return }
5154 respondJSON(w, http.StatusCreated, order)
5255}
@ari2h ago · on line 46
Nice — finally killed that io.ReadAll footgun. Can you also add a max-body limit middleware? saw a 14MB payload last week.
@noa1h ago · on line 50
Trace span name — should match the naming convention (service.operation). I'd rename to "orders.handler.create".
@tom23m ago · on line 50
Will rename in a follow-up. Filed #291. Not blocking this PR.

Conflict resolution UI

3 conflicts in 1 file · pkg/auth/middleware.go
their origin/main @b8e4d72
func AuthMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w, r) { token := r.Header.Get("X-Token") if token == "" { http.Error(w, "unauth", 401) return } h.ServeHTTP(w, r) }) }
yours feature/oauth @c1a7e83
func AuthMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w, r) { token := r.Header.Get("X-Token") token := extractBearer(r) if token == "" { respondErr(w, 401, ErrUnauth) return } h.ServeHTTP(w, r) }) }
merged resolved by devloop
func AuthMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w, r) { token := extractBearer(r) if token == "" { respondErr(w, 401, ErrUnauth) return } h.ServeHTTP(w, r) }) }
↑ ↓ nav conflict · T take theirs · Y take yours · B take both · Œ˜ E open in editor · Ž accept merge

CI/CD pipeline view

build #1284 · 7e8a912 · failed at smoke
build
go 1.22 · linux/amd64
passed · 1m 04s
test
428 specs · 2 skipped
passed · 2m 41s
deploy-staging
hetzner · v2.4.2-rc.1
deployed · 48s
smoke
12 checks · 1 failed
failed · 19s
deploy-prod
blocked by smoke
waiting
FAIL smoke/orders_create_test.go:118 · POST /v1/orders returns 201
expected status: 201
actual status: 500 Internal Server Error
body: {"error":"db: connection refused","trace":"a3f9c12-orders-create"}
→ likely cause: staging-db rolled back during canary. autopaused deploy.
→ suggested action: re-run smoke after staging-db green for 60s.
// who runs this

Built for the kind of team that ships

If you're running 4+ repos and you've ever needed to open 6 browser tabs to figure out what broke prod — yeah, this is for you.

~/small-eng-teams

2-30 engineers. Multiple repos. One dashboard.

Skip the 3 standups about who deployed what. DevLoop shows the whole team's git activity, CI runs, and open PRs on one page.

one dashboard · git · CI · deploys in a single view
~/technical-founders

Build, deploy, monitor. Stop juggling half a dozen tools to ship.

You don't need GitHub + Linear + Vercel + CircleCI + Sentry + a Notion roadmap to ship a SaaS. Cut the surface area. Keep your context.

replaces: ~4 tools · keeps: one mental model
~/contractor-teams

Multiple clients, multiple codebases, one workspace per client.

Each client gets their own DevLoop workspace. Permissions are scoped per-workspace. No more sharing GitHub orgs.

workspaces: unlimited · client-facing read-only: yes
// $ cat integrations.toml

Connects to what you already run

DevLoop doesn't want to replace your git host. It wants to be the dashboard on top of it.

integrations.toml · readonly
[git-hosts]
connects = [ "GitHub"·"GitLab"·"Bitbucket" ]
[deploy-targets]
connects = [ "Vercel"·"Netlify"·"Fly.io"·"AWS"·"Render" ]
[ci-providers]
connects = [ "CircleCI"·"GitHub Actions"·"GitLab CI" ]
[notifications]
connects = [ "Slack"·"Discord"·"Email" ]
[planned]
connects = [ "Linear"·"Sentry"·"PagerDuty"·"Datadog" ]
--webhook-signing = "hmac-sha256" · --rate-limit = "1k/min" · --retry-policy = "exponential, max=5"
// $ devloop --help | grep faq

Things you'll probably ask

If your question isn't here, the docs cover it. If the docs don't, open an issue. We'll write you back, not a bot.

A:Yes — it's the only way we run it. DevLoop ships as a docker-compose stack on a single box. Postgres + Redis + an object store (S3-compatible) and you're up. Self-host runs the same binary we run — no feature gating, no separate "community edition".
A:Yes. You can define paths (e.g. apps/web, packages/api) as logical sub-projects with their own pipelines, owners, and changelogs. Conditional CI on path changes is built-in. Turborepo and Nx are detected automatically.

Tested up to ~40 sub-projects in a single tree. Beyond that you'll want to talk to us about index sharding.
A:Secrets are handled at the docker-compose + environment level on the host that runs DevLoop — encrypted at rest with AES-256-GCM, scoped per environment (dev/staging/prod) and per repo. No third-party key service in the loop; nothing leaves the box.

You can also opt out entirely and keep secrets wherever you already keep them. We won't touch the secret values — only check they exist.
A:It doesn't replace them. DevLoop reads from your existing GitHub/GitLab/Bitbucket repos. The difference is the surface:

GitHub is excellent at hosting code and running Actions, but its dashboard was built for individuals scrolling notifications. DevLoop is built for a team looking at one screen together — your repos, your builds, your deploys, your tasks, in one terminal-shaped UI.

You keep GitHub. You add DevLoop on top.

~/start

// Open the demo. Connect a repo. Watch a deploy. That's the walkthrough.

Explore more technologies built inside NTJ.

Features in depth

Everything DevLoop does.

The boring parts of shipping software — hosting, review, testing, deploys — stay out of your way so you can stay in the code.

Git repository hosting

Push, pull, clone. The same Git workflow you already use, no new commands to learn.

Branch and PR workflow

Cut a branch, open a PR, merge when it's green. You've done this a thousand times.

Code review comments

Comment on the exact line. Threads resolve themselves once the fix lands.

CI/CD pipelines

Every push kicks off a build, runs your tests, and ships if it passes.

Automated tests

Your suite runs on every change. Pass or fail shows up right on the PR.

Deployment previews

Every PR gets its own live URL. Click it, poke at the change before you merge.

Environment management

Staging and production stay separate, each with its own config and secrets.

Issue tracker

Bugs and tasks live next to the code, linked to the branch that closes them.

Secret management

API keys stay encrypted and out of your repo. Builds get them at run time, nowhere else.

Audit log

Who changed what, and when — across repos, deploys, and settings. When something breaks, you'll know where to look.

Team permissions

Decide who can read, push, or admin each repo and environment. Scope it as tight as you need.

Custom domains

Point your domain at a deploy. Certificates renew on their own, so you don't get paged about it.

Use cases

How teams put DevLoop to work.

Reviewing a feature before it ships

You open a PR. DevLoop spins up a preview and runs your tests while you wait. Reviewers comment on the diff and approve once the checks go green — no context-switching to three other tabs.

Promoting a build to production

Merge to main and the pipeline builds it, ships it to staging, and waits. When you've had a look, promote the exact same build to production. No rebuild, no surprises.

Onboarding a new engineer

Add the new hire, give them access to the right repos, done. They clone, cut a branch, and watch their first preview deploy — without ever touching your infrastructure.

Built inside NTJ

This technology was developed inside NTJ to support marketing operations, automation, analytics, and client delivery. Availability may vary depending on the product and use case.

Some NTJ technologies are used internally, some are made available to selected clients, and others may be released publicly. This technology is not the primary service offered by NTJ — our core focus is helping businesses achieve measurable growth through better marketing.

Talk to us about your marketing needs →