Metadata-Version: 2.4
Name: piagentsync
Version: 1.0.2rc2
Summary: Sync OpenCode agents and skills from an Obsidian vault to workspace directories
License: MIT
License-File: LICENSE
Requires-Python: >=3.13
Requires-Dist: pydantic-settings>=2.3
Requires-Dist: pydantic>=2.7
Requires-Dist: python-frontmatter>=1.1
Requires-Dist: rich>=13
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# piagentsync

Sync OpenCode agents, skills, commands, and context files from an Obsidian vault to workspace directories.

## Install

```bash
uv add piagentsync
# or
pip install piagentsync
```

## Quick start

1. Initialize a new project in your vault:

```bash
piagentsync init myproject --workspace ~/workspace/myproject
```

2. Pull the synced files to your workspace:

```bash
piagentsync pull myproject
```

3. If you made edits in the workspace and want to push them back into the vault:

```bash
piagentsync push myproject
```

## Configuration

Environment variables (also configurable via `.env` file):

| Variable | Default | Description |
|----------|---------|-------------|
| `PIAGENTSYNC_VAULT_PATH` | `~/vault` | Path to Obsidian vault |
| `PIAGENTSYNC_GLOBAL_OPENCODE_PATH` | `~/.config/opencode` | Path to global OpenCode config |
| `PIAGENTSYNC_VAULT_GITHUB_USER` | `Piwero` | GitHub username for vault repository (used in clone instructions) |

## CLI reference

### `piagentsync pull <project>`

Sync a single project from vault to workspace. This synchronizes agents, skills, commands, and the AGENTS.md context file.

Options:
- `--dry-run` / `--no-dry-run` — preview changes without writing
- `--global` / `--no-global` — also sync global agents
- `--all` — sync all discovered projects

### `piagentsync push <project>`

Sync a single project from workspace back to the vault. This synchronizes agents, skills, commands, and the AGENTS.md context file. It is the inverse of `pull` and is intended for bootstrapping the vault from existing workspaces or pushing emergency/local edits back into the vault (the user is expected to review and commit the vault afterwards).

Options:
- `--dry-run` — preview what would be pushed without writing
- `--global` — also push global agents from your local global opencode config into `vault/agents/global/`
- `--all` — push all discovered projects

Behavior notes:
- Direction: workspace (`.opencode/`) → vault
- Conflict rule: workspace wins (files in the vault will be overwritten if different)
- Unchanged files are skipped using hash comparison
- After a successful push the CLI will print a reminder to run:
  `cd ~/vault && git add -A && git commit -m "..." && git push`

Auto-commit behavior
--------------------

When `piagentsync push` completes successfully (not a dry-run and no errors),
the CLI will automatically attempt to commit changes to the vault repository
using a conventional commit message (e.g. `feat(push): sync <project> from
workspace to vault`). If the auto-commit succeeds you'll see a message like
`✓ Vault committed: <git output>`. If there are no changes to commit you'll see
`No changes to commit`. If auto-commit fails, the CLI prints a warning and the
manual fallback instructions (e.g. `cd ~/vault && git add -A && git commit`).


Note: the auto-commit step requires that git is available and configured
(`user.name` and `user.email`).

### `piagentsync sync <project>`

Bidirectional sync with automatic conflict detection and resolution.

Performs intelligent two-way sync of agents, skills, commands, and context files:
- Files unchanged in both locations: synced normally
- Files changed only in one location: synced from that location
- Files changed in both locations: resolved by conflict resolution strategy

#### Conflict resolution strategies:

- `--strategy vault-wins` — vault version always wins (push workspace edits → conflicts resolve to vault)
- `--strategy workspace-wins` — workspace version always wins (pull edits → conflicts resolve to workspace)
- `--strategy ask` — **default** — report conflicts without auto-resolving (human review required)

**Examples:**

```bash
# Show conflicts without auto-resolving (default):
piagentsync sync myproject

# Auto-resolve to vault version:
piagentsync sync myproject --strategy vault-wins

# Auto-resolve to workspace version:
piagentsync sync myproject --strategy workspace-wins

# Sync all projects with auto-resolution:
piagentsync sync --all --strategy workspace-wins
```

**Legacy flags** (still supported but deprecated):
- `--vault-wins` — equivalent to `--strategy vault-wins`
- `--workspace-wins` — equivalent to `--strategy workspace-wins`

Do not mix old and new flags (will error).

Options:
- `--dry-run` / `--no-dry-run` — preview changes without writing
- `--global` / `--no-global` — also sync global agents
- `--all` — sync all discovered projects

WORKSPACE_WINS behavior and auto-commit
--------------------------------------

The `workspace-wins` strategy writes the workspace copy back into the vault
(destination → source). When `piagentsync sync` runs without `--dry-run` and
completes successfully, the CLI will attempt to auto-commit changes to the
vault repository. Use `--dry-run` to preview changes without writing.

Example (dry-run, will not write):

```bash
piagentsync sync myproject --strategy workspace-wins --dry-run
```

### `piagentsync status [project]`

Show sync status (differences between vault and workspace) for agents, skills, commands, and context files.

By default shows both project agents and global agents. Use `--no-global` to show only project agents.

Options:
- `--global` / `--no-global` — toggle global agent display (default: shows global agents)

**Examples:**

```bash
# Show status for all projects (includes global agents by default):
piagentsync status

# Show status for a specific project (includes global agents by default):
piagentsync status myproject

# Show only project agents (exclude global agents):
piagentsync status --no-global

# Show only global agents:
# To view global agents only, run `piagentsync status` and filter the "Project"
# column for `global`, or explicitly request a global-only view by running the
# command on a machine configured with only global agents. The CLI currently
# shows project and global agents together by default; use `--no-global` to
# exclude global agents.
```

### `piagentsync init <project>`

Scaffold a new project in the vault.

Options:
- `--workspace PATH` — required, workspace directory
- `--notion-board-id TEXT` — optional Notion DB ID
- `--notion-project-filter TEXT` — optional Notion project filter (defaults to project slug)

### `piagentsync bootstrap`

Bootstrap machine from an existing vault. This is a one‑time setup to configure OpenCode and install global agents.

Options:
- `--force` — overwrite existing `opencode.json` if present

Steps performed:
1. Verifies that the vault exists (`PIAGENTSYNC_VAULT_PATH`). If missing, prints a helpful `git clone` command.
2. Writes `{PIAGENTSYNC_GLOBAL_OPENCODE_PATH}/opencode.json` with Notion and Obsidian MCPs and disables tool globs. Skips if file exists unless `--force` is used.
3. Runs `opencode mcp auth notion` interactively to authenticate with Notion. If `opencode` is not on PATH, a warning is printed and the step is skipped.
4. Copies the `chief-pm` global agent from the vault's configuration into your global OpenCode config. For new-style vaults this is `{vault}/config/agents/global/chief-pm.md`; for legacy vaults it is `{vault}/agents/global/chief-pm.md`. If neither exists, a warning is printed.

All steps produce clear Rich output and non‑critical warnings. The command exits 1 only if the vault is missing or a file write fails.

### `--version`

Print version and exit.

## AGENTS.md manifest format

Each project must have an `AGENTS.md` file in its root with YAML frontmatter:

```yaml
---
project: myproject
workspace: ~/workspace/myproject
notion_board_id: 3305f9479a8d8055b3c3e86a9006cf91
notion_project_filter: myproject
---
```

The body below the frontmatter is the OpenCode routing table.

## Expected vault structure

### New layout (recommended)

```
vault/
├── config/                 # Global OpenCode configuration
│   ├── agents/            # Global agents
│   │   └── global/       #   agents available in all projects
│   │       └── *.md
│   ├── commands/          # Global commands
│   │   └── global/
│   │       └── *.md
│   └── tools/             # Tool documentation (*.md)
└── projects/              # Project-specific configuration
    └── {project}/
        ├── AGENTS.md      # Project manifest (required)
        ├── context.md     # Optional project context
        ├── decisions.md   # Optional decisions log
        ├── agents/        # Project-specific agents
        │   └── *.md
        ├── skills/        # Project-specific skills
        │   └── *.md
        └── commands/      # Project-specific commands
            └── *.md
```

### Legacy layout (still supported)

```
vault/
├── agents/
│   └── global/
│       └── *.md
└── agents/
    └── projects/
        └── {project}/
            ├── AGENTS.md
            ├── agents/
            │   └── *.md
            ├── skills/
            │   └── *.md
            └── commands/
                └── *.md
```

The CLI automatically detects which layout you are using. New projects created with `piagentsync init` will use the new layout if the vault contains a `projects/` directory at the root; otherwise the legacy layout under `agents/projects/` is used.

### Migrating from legacy layout

If your vault still uses the legacy layout (`agents/projects/` and `agents/global/`), you can continue using piagentsync without changes — the CLI automatically falls back to the legacy paths. To migrate to the new layout:

1. Create a `projects/` directory at the vault root.
2. Move each project from `agents/projects/<project>/` to `projects/<project>/`.
3. Move global agents from `agents/global/` to `config/agents/global/` (create the `config/` directory as needed).
4. Optionally, move global commands from `commands/global/` to `config/commands/global/`.
5. Remove the old `agents/projects/` and `agents/global/` directories once you have verified the new layout works.

The legacy layout will remain supported for the foreseeable future.

Commands not yet documented or experimental
------------------------------------------

- watch: The `watch` command is polling-based and checks the vault git
  repository for new commits every `--interval` seconds (minimum 10). When it
  detects new commits, it determines affected projects and prints a message
  indicating which projects were synced. Note: the watcher currently prints
  which projects are affected and contains a TODO placeholder in the code where
  a full sync could be triggered. We therefore mark `watch` as experimental
  until the automatic sync implementation is finished.


## Contributing

Development setup:

```bash
uv sync
uv run pytest
```

Lint and format:

```bash
uv run ruff check src/ tests/
uv run ruff format src/ tests/
```

Type checking (MyPy)
--------------------

We use strict mypy checks for the codebase. To run type checking locally:

```bash
uv run mypy src/ tests/ --strict
```

Notes:
- The repository includes a `py.typed` marker so the package is PEP-561 compatible.
- Pre-commit runs `ruff` (format + lint). Running mypy in pre-commit was avoided due to isolated pre-commit environments — instead run mypy manually or add it to CI for consistent enforcement.

Test files to check
-------------------

If you want to run the tests that validate sync and diff behavior locally, run:

- tests/test_sync.py::test_sync_entries_workspace_wins_writes_to_vault
- tests/test_cli.py::test_status_diff_shows_absolute_paths_and_legend


All commits follow [Conventional Commits](https://www.conventionalcommits.org/).

### Publishing (maintainers)

This repository uses GitHub Actions for CI and automated releases.

#### One-time PyPI setup (trusted publisher)

1. Enable OIDC on PyPI for the repository:
   - Publisher: GitHub Actions
   - Repository owner: `Piwero`
   - Repository name: `piagentsync`
   - Workflow filename: `release.yml`
   - Environment name: (leave blank)

2. The Release workflow handles everything: bump version, create tag, build, publish to PyPI, and create a GitHub Release.

#### Release process

```text
git push → ci.yml passes
   → trigger release.yml (choose MAJOR/MINOR/PATCH/RC)
       → tests re-run → changelog generated → version bumped → tag pushed
       → GitHub Release created with assets → package published to PyPI
```

## License

MIT
