Papers
Topics
Authors
Recent
2000 character limit reached

Runnable Directory: Modular DevOps Unit

Updated 5 December 2025
  • Runnable Directory is a self-contained unit of code and DevOps configuration that enables independent build, test, and deployment processes.
  • It includes essential elements such as a mandatory rundir.yaml, Dockerfiles, source code directories, and optional nested directories for hierarchical composition.
  • Its design reconciles the trade-offs between monorepos and multi-repos by supporting isolated dependencies and streamlined, dependency-aware CI/CD pipelines.

A runnable directory is a self-contained unit of code and DevOps configuration that can be independently built, tested, and deployed, while also serving as a composable building block within larger systems. Originating as the central concept of the Causify Dev system, the runnable directory formalizes a hybrid approach to codebase organization that reconciles the trade-offs between monolithic repositories (monorepos) and fine-grained multi-repositories. The core motivation is to enable scalable, modular development and continuous integration in complex software projects, especially where consistent setup, isolated dependencies, and efficient CI/CD are paramount (Ghasemnezhad et al., 3 Dec 2025).

1. Formal Specification and Structural Anatomy

A runnable directory is defined as a directory DD containing:

  • A mandatory rundir.yaml configuration file
  • One or more Dockerfiles (for multi-stage container builds)
  • Source code subdirectories (e.g., src/, tests/)
  • A Git submodule pointer (typically to a shared “helpers” repository)
  • Optionally, nested runnable directories (permitting hierarchical composition)

The formal structural grammar (BNF):

1
2
3
4
5
6
7
<RunnableDir> ::= DirectoryName "/"
                 files: { RundirConfig, Dockerfile+, SourceTree, [SubRunnableDirs] }

RundirConfig   ::= "rundir.yaml"
Dockerfile     ::= "Dockerfile" [".local" | ".dev" | ".prod"]
SourceTree     ::= { *.py | *.js | *.go | ... }
SubRunnableDirs ::= <RunnableDir>+

The configuration is formalized as:

RD=(id,Dcode,Dcfg,Dops,Deps)\mathrm{RD} = (\,\mathit{id},\,\mathit{D}_\mathit{code},\,\mathit{D}_\mathit{cfg},\,\mathit{D}_\mathit{ops},\,\mathit{Deps}\,)

Where id\mathit{id} is a unique string identifier; Dcode\mathit{D}_\mathit{code} is the code tree; Dcfg={rundir.yaml}\mathit{D}_\mathit{cfg} = \{\texttt{rundir.yaml}\}; Dops\mathit{D}_\mathit{ops} contains automation/configuration files; Deps\mathit{Deps} is the set of other runnable directory pointers.

Example rundir.yaml:

1
2
3
4
5
6
7
8
9
10
11
id: "service-payment"
docker:
  context: "."
  image: "causify/service-payment"
  tags: ["latest", "dev"]
storage:
  s3_bucket: "causify-artifacts"
  s3_path: "service-payment"
dependencies:
  - "../helpers"
  - "../common-utils"

2. Unified Thin Environment and Core Tooling

The “thin environment” is a minimal, host-agnostic bootstrap per developer or CI/automation agent. It consists of:

  • A Python virtual environment, providing:
    • Docker CLI (plus Docker Desktop/WSL for non-Linux systems)
    • The invoke Python-based task runner
    • Causify system client commands (e.g., causify bootstrap, causify run)
  • A Git submodule for shared “helpers,” delivering:
    • Standardized build/test/deploy scripts (via invoke)
    • Git hooks for policy, lint, and secret-scan enforcement
    • Symbolic links for shared configs (e.g., LICENSE, CI templates)

Container workflows are coordinated via per-directory Dockerfiles with multi-stage builds (local, dev, prod) and standardized invocation through the thin environment’s scripts. Docker Compose or Docker-in-Docker enable multi-container orchestration: sibling containers share the host Docker daemon, while child containers facilitate nested build/test scenarios (Ghasemnezhad et al., 3 Dec 2025).

3. Dependency Graphs and Isolation

Dependencies in the runnable directory paradigm are twofold:

  • Intra-code dependencies: Relationships between runnable directories, represented as a directed graph G=(V,E)G = (V, E) with VV the set of runnable directories and (i,j)E(i, j) \in E if RDi\mathrm{RD}_i depends on RDj\mathrm{RD}_j. Any topological sort provides a valid build and test order; dependency cycles are disallowed.
  • Third-party dependencies: Specified and resolved per-directory (e.g., via requirements.txt for Python), captured explicitly in container build steps.

This two-tiered isolation ensures per-directory dependency resolution: disjoint subgraphs of GG may pin differing morphs of a library without risk of global conflict.

Dependency Type Resolution Scope Artifact
Intra-RD Globally (across RDs) Directed acyclic graph (dependency order)
Third-Party Library Per RD/container Per-directory package manifest, Dockerfile

4. CI/CD Integration and Lifecycle Stages

Each runnable directory encapsulates its own independent CI/CD workflow. Standardized invoke tasks drive the sequence: build, test, and deploy, with isolation at the container level.

Pipeline overview:

1
2
3
4
5
6
7
8
9
10
11
Developer         | 
 | git push RD_i  | 
v
CI Server 
 | checkout RD_i
 | invoke bootstrap
 | invoke build      # docker build --tag causify/RD_i:dev
 | invoke test       # pytest or other, inside container
 | invoke deploy     # push & deploy container
v
Container registry / prod

Each stage—local development, dev image (registry), production—utilizes tagged Docker images for traceability.

Example CI snippet (condensed):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup thin env
        run: |
          python3 -m venv .venv
          source .venv/bin/activate
          pip install invoke docker
      - name: Build container
        run: invoke build
      - name: Run tests
        run: invoke test
  deploy:
    needs: build-and-test
    if: github.ref == 'refs/heads/main'
    steps:
      - run: invoke deploy

A plausible implication is that recursive execution and dependency-awareness minimize the CI build/test surface upon code changes, contrasting with monolithic or multi-repo systems where coordination granularity or sprawl impose wider blast radii.

5. Comparative Evaluation with Monorepo and Multi-repo

The runnable directory model, as exemplified by Causify Dev, integrates aspects of monorepo and multi-repo architectures:

  • Monorepo: Offers global consistency, single history, cross-project atomicity; in practice, incurs giant build/test surfaces and warrant specialized tooling (e.g., Bazel, Buck), presenting friction for permissioning and scalability.
  • Multi-repo: Grants project isolation and small surface area; prone to version skew, coordination friction, and complex cross-repo refactoring.
  • Runnable Directory (Causify Dev):
    • Gains modularity and independent release cadence at the directory level (like multi-repo)
    • Maintains shared “thin” bootstrap and helpers (like monorepo)
    • Avoids heavyweight orchestrators, supporting recursive, dependency-aware build/test pipelines

Trade-offs include required Docker proficiency and the cognitive overhead of submodules and configuration management. The necessity for mastering the thin environment and the invoke pattern is explicitly noted (Ghasemnezhad et al., 3 Dec 2025).

6. Qualitative Impact and Adoption

While external benchmarks and quantitative performance metrics are not furnished, the internally reported results at Causify AI indicate:

  • Almost zero “works-on-my-machine” discrepancies
  • A single shared “helpers” submodule replaced duplicative scripts across a dozen services
  • Onboarding time for engineers was reduced to under 15 minutes, compared to days with prior monorepo setups

Teams leverage directory-level pipelines and dependency isolation to reduce both build times and infrastructural churn. Future directions outlined include: dependency-aware CI caching, fully parallelized CI across RDs, and automated generation of .dockerignore files to further decrease build/test resource consumption (Ghasemnezhad et al., 3 Dec 2025).

7. Extensions, Scalability, and Future Prospects

Proposed extensions to the runnable directory paradigm include:

  • Improved CI acceleration via parallelization and dependency-sensitive caching
  • Automated configuration management, including but not limited to the dynamic generation of .dockerignore
  • Enhanced support for federated workflows beyond a single organization, through linked-data endpoints or external registry federation

A plausible implication is that the model scales naturally by distributing encapsulation and control, thus accommodating large teams and diverse, polyglot codebases without global coordination bottlenecks.


For primary sources and further formalism, see "Runnable Directories: The Solution to the Monorepo vs. Multi-repo Debate" (Ghasemnezhad et al., 3 Dec 2025).

Definition Search Book Streamline Icon: https://streamlinehq.com
References (1)
Slide Deck Streamline Icon: https://streamlinehq.com

Whiteboard

Forward Email Streamline Icon: https://streamlinehq.com

Follow Topic

Get notified by email when new papers are published related to Runnable Directory.