Working With Us

We're not hiring. But here's the kind of people we want building Kazisafi with us when the time comes.

We’re not hiring. No open role, no listing, no urgency. We’re bootstrapped and before market - this isn’t a call for applications.

But we’ve been thinking about who we’d want building Kazisafi with us when the time comes, and it felt worth writing down. Partly so the right person finds it. Partly to be honest about what we value before there’s pressure to fill a seat.

What Kazisafi Is

A payroll platform for Kenyan SMEs. A Rails monolith handling statutory compliance, M-Pesa disbursements, leave, attendance, and invoicing. Opinionated and well-organized. We intend to keep it that way.

Managers of One

The phrase is Basecamp’s: people who set their own direction and don’t need checking in on every few hours. We’re small and building foundational systems, so no one has a narrow lane. You pick up the ticket, learn the domain, ship the feature, write the tests. If it breaks in production, you fix it - because you noticed, not because someone assigned it.

Not heroics, not long hours. Ownership. You have full context, you make the call, and you say something when something’s off.

The Code

Rails 8, Hotwire, PostgreSQL, Redis, Sidekiq, deployed with Kamal to Hetzner. Server-rendered HTML, Stimulus for behavior. No React, no build step, no client-side state.

The conventions are strict, so rather than list them - one example. When a manager approves a leave request, the controller does almost nothing:

def create
@form = Leave::ApproveForm.new(leave_request: @leave_request, attributes: approve_params)
if @form.save
confirmed notice: "Leave request approved", redirect_url: leave_requests_path, refresh: true
else
confirmation_failed alert: @form.errors.full_messages.to_sentence
end
end

No business rules, no Current.company bookkeeping - a scoping concern already loaded a tenant-scoped request. The controller hands off to a form, the form calls the model, and the model - not the controller - is what reaches the operation that does the work:

def approve(by:, comments: nil)
Leave::Request::Approval.call(request: self, approver: by, comments:)
end

So request.approve(by: manager) reads like a sentence, and nothing outside the model knows an operation is involved. The operation authorizes, snapshots the balance, emits an event, and lets the model own its own pending → approved transition. Four layers, each seeing only the one below it - testable in isolation, boring to change.

The rest, briefly:

  • Domain-namespaced models - payroll with payroll, leave with leave
  • ViewComponents over partials - explicit interfaces, testable
  • Composable filter objects - one per index page, no where clauses in controllers
  • Event-driven side effects - operations emit, notifiers subscribe, mailers deliver
  • Open Props for every CSS value - no magic numbers

If that looks familiar, good. If not but you’re curious, the patterns are documented and consistent. You’d learn them.

Person-Driven, AI-Assisted

We use Claude Code - a multiplier, not a crutch. The rules files, architecture docs, and strict conventions exist partly so the tooling can follow the patterns. It works because the patterns are clear. The ratio is 75:25: you drive, the AI assists.

You need to understand why - why the controller doesn’t reach past the form, why the model hides the operation, why a filter returns the scope untouched when there’s nothing to filter. If you can’t, the AI won’t bridge the gap. It’ll just generate confident code that doesn’t belong.

What We’re Looking For

You’d own features end to end - the PAYE calculator across progressive tax bands, the KRA-compliant P10 generator, the background job, the Turbo frame, and the tests that make sure a shilling never goes missing.

The domains are genuinely hard: NSSF two-tier contributions, SHIF, housing levy, PAYE with insurance and pension relief, the Employment Act’s one-third rule; leave balances with carryover expiry; sub-10ms biometric clock-ins. What matters:

  • Strong Rails fundamentals - and knowing when not to reach for them
  • Hotwire fluency - Turbo Frames, Streams, Stimulus controllers that do one thing
  • CSS without frameworks - Open Props, BEM, mobile-first, dark mode
  • PostgreSQL comfort - efficient queries, JSONB, no N+1s
  • Testing discipline - RSpec where it earns its keep, not coverage theater
  • Curiosity about the domain - payroll isn’t glamorous, but getting it wrong costs people money

Not someone who’s done everything. Someone who figures things out and ships clean work.

What’s Ahead

The core engine works. Now it gets interesting.

Payments. Salary disbursements, invoice settlements, contractor payouts - M-Pesa B2C, PesaLink, eventually direct bank transfers. Idempotency keys, reconciliation loops, and what to do when a provider returns an ambiguous response at 2am.

Mobile. Hotwire Native wrapping the existing app into iOS and Android shells. Same codebase, same server-rendered HTML, native navigation and push. The one-person framework, extended to the app store.

There’s more we’re not ready to talk about. But the shape is clear: real infrastructure, real complexity, real impact on how Kenyan businesses run payroll.

How We Work

  • Async-first. No standups. We work through Fizzy with enough context that no one needs a meeting.
  • Deadlines over hours. Delivery matters, not time logged.
  • Deliberately, not frantically. This handles salaries. No cutting corners on financial logic or compliance.
  • Simplicity. Three clear lines over a clever abstraction. Optimize for whoever reads it in six months.
  • Have a life. Non-negotiable. Rested people write better code.

What This Isn’t

Not a job posting. No application form, no pipeline, no timeline. We’re bootstrapped and pre-revenue, building something we believe in.

But if you read this far and something landed - the architecture, the conventions, the way we work - we’d like to know you exist. Reach out at [email protected]. Tell us what you’ve built and what you care about. Skip the cover letter and the CV.