Metadata-Version: 2.3
Name: tlc-shared-docs
Version: 1.1.16
Summary: Share documentation files between Git repositories
License: MIT
Requires-Python: >=3.9,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: gitpython (>=3.1,<4.0)
Description-Content-Type: text/markdown

# tlc-shared-docs

Share documentation files between Git repositories. Pull files from a remote repo into your local docs tree, or push local files back — all configured through a single `shared.json`.

## Installation

```bash
pip install tlc-shared-docs
```

## Quick Start

### 1. Create the config

Create `docs/source/shared/shared.json` in your project:

```json
{
  "source_repo": {
    "url": "https://github.com/your-org/shared-docs.git",
    "branch": "main"
  },
  "shared_files": [
    {
      "remote_path": "guides/getting-started.md",
      "local_path": "getting-started.md",
      "action": "get"
    },
    {
      "remote_path": "guides/api-reference.md",
      "local_path": "api-reference.md",
      "action": "push"
    }
  ]
}
```

### 2. Pull shared files

```bash
tlc-shared-docs get
```

This fetches every file with `"action": "get"` from the remote repo and saves it locally.

### 3. Push local files

```bash
tlc-shared-docs push
```

This pushes every file with `"action": "push"` to the remote repo. If a remote file has changed since you last pulled, the command aborts with a conflict warning. Use `--force` to overwrite:

```bash
tlc-shared-docs push --force
```

### 4. Preview changes

Both commands support `--dry-run`:

```bash
tlc-shared-docs get --dry-run
tlc-shared-docs push --dry-run
```

## Configuration Reference

### `shared.json`

| Field | Description |
|---|---|
| `source_repo.url` | Git clone URL for the shared repo |
| `source_repo.branch` | Branch to pull from / push to (default: `main`) |
| `shared_files[].remote_path` | Path to the file in the remote repo (supports glob patterns for `get`) |
| `shared_files[].local_path` | Local destination path (relative to `docs/source/shared/`) |
| `shared_files[].action` | `get` (pull from remote) or `push` (push to remote). Default: `get` |

### Wildcard / glob patterns

The `remote_path` field supports glob patterns for `get` actions, allowing you to fetch multiple files with a single entry:

```json
{
  "remote_path": "stories/**/*",
  "local_path": "stories",
  "action": "get"
}
```

Supported patterns:
- `*` — matches any file in a single directory (e.g., `docs/*.md`)
- `**/*` — matches files recursively across directories (e.g., `stories/**/*`)
- `?` — matches a single character (e.g., `chapter?.md`)
- `[seq]` — matches any character in the set (e.g., `file[0-9].txt`)

When using globs, `local_path` acts as the **destination directory**. Matched files preserve their directory structure relative to the non-glob prefix of the pattern. For example:

| Pattern | Matched remote file | `local_path` | Written to |
|---|---|---|---|
| `stories/**/*` | `stories/ch1/intro.md` | `mystories` | `mystories/ch1/intro.md` |
| `Global/*.gitignore` | `Global/Vim.gitignore` | `ignores` | `ignores/Vim.gitignore` |
| `*.md` | `README.md` | `docs` | `docs/README.md` |

### Local path resolution

- **Relative paths** (e.g., `guide.md`) resolve relative to `docs/source/shared/`.
- **Absolute paths** (starting with `/`, e.g., `/src/docs/guide.md`) resolve relative to the project root.

### Git ignore

On first run, `tlc-shared-docs get` creates `docs/source/shared/` with a `.gitignore` that tracks only `shared.json` — all fetched files are ignored so they don't bloat your repo.

The auto-generated `docs/source/shared/.gitignore` contains:

```gitignore
# Auto-generated by tlc-shared-docs
# Ignore all fetched shared files; only track the config
*
!.gitignore
!shared.json
```

This means:
- `shared.json` is committed to your repo (so teammates share the same config)
- All fetched/pushed doc files are ignored locally
- The `.gitignore` itself is also tracked

#### Versioning specific shared files in your own repo

The `.gitignore` is written once and never overwritten by `tlc-shared-docs`. You can edit it freely to commit specific shared files to your own repo.

For example, to version-control `getting-started.md` and everything under `guides/` while still ignoring everything else:

```gitignore
# Auto-generated by tlc-shared-docs
# Ignore all fetched shared files; only track the config
*
!.gitignore
!shared.json

# Files I want to version in THIS repo:
!getting-started.md
!guides/
!guides/**
```

This is useful when your team wants certain shared docs to appear in your repo's git history — for example, files that are reviewed during PRs or that tools like GitHub Pages need to find in the repository.

### Central mode

Central mode lets an architecture repo control what documentation each consumer repo receives. The consumer's `shared.json` just points at the source repo with `"mode": "central"` — the architecture repo decides the rest.

> **Setting up central mode?** See [README_CENTRAL.md](README_CENTRAL.md) for a detailed walkthrough covering architecture repo setup, per-consumer config files, identity detection, permissions, and the full end-to-end flow.

### Auto-uploading new files (central mode)

When running in **central mode**, consumer repos can automatically upload new files to the shared repo. The central config controls which paths are allowed:

```json
{
  "shared_files": [
    { "remote_path": "guides/intro.md", "local_path": "intro.md", "action": "get" }
  ],
  "uploads": {
    "allowed": true,
    "paths": [
      "contributions/**/*.md",
      "images/*.png"
    ]
  }
}
```

| Field | Description |
|---|---|
| `uploads.allowed` | Set to `true` to enable auto-upload for this repo |
| `uploads.paths` | Glob patterns for permitted remote paths (supports `*`, `**`, `?`) |

#### How it works

1. Place new files anywhere under `docs/source/shared/` in your local repo.
2. Run `tlc-shared-docs push`. The tool automatically scans for files that are **not** already listed in `shared_files`.
3. Each new file's path (relative to `docs/source/shared/`) is checked against the `uploads.paths` patterns.
   - **Permitted** files are included in the push commit.
   - **Denied** files produce a `DENIED:` warning and are skipped.
4. Use `--dry-run` to preview which files would be uploaded or denied.

```bash
# Preview what would be uploaded
tlc-shared-docs push --dry-run

# Push configured files + upload new ones
tlc-shared-docs push

# Force-push (skip conflict check)
tlc-shared-docs push --force
```

> **Note:** Auto-upload only works in central mode. In local mode, add new entries directly to your `shared.json` `shared_files` list.

### Multi-project configs

If your repo participates in multiple architecture projects (e.g., auth, events, agent-coder), you can define them all in a single `shared.json` and select which one to use at runtime:

```json
{
  "projects": {
    "auth": {
      "source_repo": { "url": "https://github.com/your-org/tlc-auth-arch.git" },
      "mode": "central"
    },
    "events": {
      "source_repo": { "url": "https://github.com/your-org/tlc-events-arch.git", "branch": "dev" },
      "mode": "central"
    },
    "agent-coder": {
      "source_repo": { "url": "https://github.com/your-org/agent-coder.git" },
      "mode": "central"
    }
  },
  "default_project": "agent-coder"
}
```

Each project entry supports the same fields as the legacy single-source format (`source_repo`, `mode`, `shared_files`, `uploads`).

#### Usage

```bash
# See what projects are available
tlc-shared-docs list

# Pull docs for a specific project
tlc-shared-docs get --project agent-coder
tlc-shared-docs get -p auth

# Uses default_project when --project is omitted
tlc-shared-docs get

# Push works the same way
tlc-shared-docs push -p events --dry-run
```

The `list` command shows all available projects with their source URLs, branches, and modes — useful when you don't know the exact project name.

| Field | Description |
|---|---|
| `projects.<name>` | A named project entry (same schema as legacy root config) |
| `default_project` | Project to use when `--project` is not specified |

If no `--project` flag is given and no `default_project` is set, the command exits with an error listing available projects.

#### Automatic file isolation

In multi-project mode, each project's files are automatically placed into a subdirectory named after the project. You don't need to manually prefix `local_path` — it's handled for you:

```
docs/source/shared/
├── shared.json
├── auth/              ← files from the "auth" project
│   └── guide.md
├── events/            ← files from the "events" project
│   └── architecture.md
└── agent-coder/       ← files from the "agent-coder" project
    └── spec.md
```

For example, if the central config for the `agent-coder` project defines `"local_path": "spec.md"`, the file is written to `docs/source/shared/agent-coder/spec.md`. Absolute paths (starting with `/`) bypass this prefix and resolve from the project root as usual.

#### Project name rules

Project names must be valid folder names: alphanumerics, hyphens, underscores, and dots, starting with a letter or digit. Invalid names (e.g., `../escape`, names with spaces or special characters) are rejected at config load time.

> **Backward compatibility:** The legacy single-source format (with `source_repo` at the root) still works exactly as before — no prefixing, no migration needed.

### Claude agent skills

If you use [Claude Code](https://claude.com/claude-code) or other Claude-based agents, you can install a skill file that teaches the agent how to work with `tlc-shared-docs` in your repo.

#### Available skills

| Skill | For | Description |
|---|---|---|
| `player1` | Architecture repos | Teaches Claude how to manage `.configs/`, onboard consumers, and maintain shared docs |
| `player2` | Consumer repos | Teaches Claude how to pull/push shared docs, use `--dry-run`, and contribute new files |

You can install both in the same repo if it acts as both an architecture repo and a consumer.

#### Installing a skill

```bash
# For architecture repos (central/source of shared docs)
tlc-shared-docs init --skill player1

# For consumer repos (pull/push shared docs from an arch repo)
tlc-shared-docs init --skill player2

# Both can coexist in the same repo
tlc-shared-docs init --skill player1
tlc-shared-docs init --skill player2
```

This does two things:
1. Writes the skill instructions to `.claude/tlc-shared-docs-<skill>.md`
2. Adds a generic reference block to `CLAUDE.md` (with HTML comment markers) that directs Claude to read all installed skill files

Re-running `init` always overwrites the skill file with the latest content and replaces the `CLAUDE.md` block in-place — safe to run repeatedly.

#### When does Claude use the skill?

Claude reads `CLAUDE.md` at the start of every conversation. The reference block tells it to read all `.claude/tlc-shared-docs-*.md` files whenever you mention:
- shared docs / shared documents / shared files
- document sharing / doc sharing / doc sync
- `.configs/` / consumer configs / architecture docs
- `tlc-shared-docs`

No special syntax needed — just talk naturally about shared docs and Claude will know what to do.

If both player1 and player2 are installed, Claude reads both and asks for clarification when it's ambiguous whether you mean docs managed by this repo or consumed from a remote.

## Requirements

- Python 3.9+
- Git installed and on `PATH`
- Valid Git credentials for the source repo

