---
title: "Keep internals private · Agent Wranglers"
url: https://agentwranglers.se/playbook/architecture/coupling/private-internals
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep internals private

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [Coupling](https://agentwranglers.se/playbook/architecture/coupling)
- Rule: Each module exports only what its callers need. Everything else stays private, so it can change without breaking anyone.
- How: Mark helpers private or keep them out of the module's public entry file. Give each package one public entry point. Callers never import from another module's internal folders.
- Check: A tool fails on unused exports and on imports of another module's internals. Examples are knip or vulture for unused code, and dependency-cruiser for JavaScript, Deptrac for PHP or import-linter for Python for internal imports.

Example:

```js
// Bad: callers reach into the module's internals
import { formatLine } from '../invoices/internal/format.js';

// Good: one public entry point, internals stay hidden
import { renderInvoice } from '../invoices/index.js';
```

```python
# invoices/__init__.py: the package's one public entry point
from .render import render_invoice

__all__ = ["render_invoice"]

# Callers write: from invoices import render_invoice
# Helpers in invoices/_format.py start with an underscore and stay private
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers architecture playbook: https://agentwranglers.se/playbook/architecture/coupling/private-internals`.

- Previous: [Pass state in instead of sharing globals](https://agentwranglers.se/playbook/architecture/coupling/no-global-state)
- [Coupling](https://agentwranglers.se/playbook/architecture/coupling)
