NTEK Operations Repo — PRD

Version: 1.4 Owner: Ben Eichholz Status: Draft Last Updated: 2026-04-20
Changelog

1. Summary

ntek-operations is a private GitHub repository that serves as NTEK AI's operational brain: the single source of truth for documentation, SOPs, runbooks, CRM data, tasks, projects, client and MCP records, time tracking, agent playbooks, and infrastructure-as-code. It sits alongside — and is actively managed by — EasyCC and Claude Code as the primary agent runtimes. Binary assets and transactional state (e-signature, invoicing, scheduling, email delivery, secrets) live in specialized SaaS tools linked from the repo. The repo holds the why, the how, and — for v1 — also what’s happening now for CRM state, task state, and logged hours.

2. Problem Statement

NTEK's current operating model has three compounding issues:

  1. Onboarding friction. New client onboardings frequently hit permissions and configuration gaps live, in front of the end user — destroying the first-impression moment.
  2. No central documentation. Per-client and per-MCP configuration, auth models, and validation steps live in scattered notes, chat threads, and tribal memory. There is no reliable way to answer “what’s the current state of Tegre’s SharePoint MCP integration?” without reconstructing it. Worse, lessons learned on one client’s SharePoint setup don’t carry forward to the next client’s.
  3. No leverage from accumulated context. Every new engagement re-learns things already learned. Playbooks, validation prompts, auth patterns, and known platform gotchas aren’t reusable because they aren’t written down in a queryable form.

A structured, git-versioned, agent-queryable operational repository addresses all three: it forces configuration to become explicit, makes state changes auditable, gives EasyCC and Claude Code a stable substrate to reason over, and — critically — accumulates MCP-level knowledge that makes each subsequent client onboarding cheaper than the last.

3. Goals & Non-Goals

Goals

Non-Goals (v1)

4. Users & Access

UserAccessInteraction Mode
BenAdminDirect git + EasyCC + Claude Code
MatthewWriteDirect git + EasyCC + Claude Code
SecuroNoneGenerated reports only, delivered via Outlook/SharePoint
TegreNoneClient-facing outputs delivered via SharePoint
Future contractorsDeferredAccess model TBD when need arises

Repo visibility: Private.

5. Architecture

5.1 Core systems

SystemRoleRepo Interaction
GitHub (ntek-operations)Context, SOPs, playbooks, IaC, agent workflows, CRM, tasks, projects, time entries, derived intelligencePrimary read/write
SharePoint / OneDriveBinary assets, client deliverablesRead + write via MCP

5.2 Specialized systems

SystemRoleAgent Interaction
OutlookHuman email (inbound + outbound)Read for signal, draft for review
ResendTransactional/automated emailWrite-only via EasyCC flows
CalendlySchedulingRead for calendar context
PandaDocE-signatureRead for contract status
StripeInvoicing, paymentsRead for payment state
AiriaAI gateway, meeting notetaker, agent runtimeConfigured via IaC; notetaker read via MCP; nightly drift detection
1Password BusinessSecrets managementRead via MCP, op CLI, and GitHub Actions service account

Harvest is intentionally absent — time tracking moved in-repo. See §7.7 and §11.4.

5.3 Systems vs. MCPs: two-layer model for MCPs

This is a conceptual split that threads through the repo structure, the matrix, and the governance rules. Worth stating carefully upfront because it shapes the inheritance model in §7.2.

Some platforms appear as both a system and an MCP — SharePoint is both a system (NTEK’s own file storage, configured once) and an MCP (per-client Graph integration, configured per engagement). The records live in different directories and describe different things.

A system is a platform we operate in. An MCP is an integration we set up for a client. Systems are cross-client; MCPs are per-client but backed by a shared MCP-type record.

The MCP-type record is authoritative for everything not client-specific. The per-client record inherits from it and only captures client-specific configuration, state, and overrides. When a lesson is learned during a client onboarding, it is written to the MCP-type record unless it’s truly unique to that client.

If the same underlying platform serves both system and MCP roles, it gets one record in systems/, one record in mcps/, and one record per client in clients/<n>/mcps/.

5.4 Source-of-truth hierarchy

When systems disagree:

5.5 Runtime

5.6 Known pain points and mitigation strategy

Running CRM, tasks, and time in git rather than dedicated SaaS tools introduces known friction points. We accept these in v1 and address them with specific mitigations. If mitigations prove insufficient, v1.5 revisits.

Pain PointExpected OnsetMitigation
Mobile capture deferred entirelyWeek 1–2Desktop-only capture; end-of-day briefing nudges for anything unlogged
Desktop-only time entry frictionWeek 1–2/track slash command + end-of-day nudge from briefing agent
Notification gapsWeek 2–3Resend push + Pushover/IFTTT for narrowly-scoped time-critical thresholds (§9)
Partner (Matthew) update frictionMonth 1–2Slash commands that make structured commits 1-step
View layer pain (pipeline boards, calendars)Month 2–3CI generates rendered dashboards from markdown source into _generated/

6. Repository Structure

ntek-operations/
├── README.md                          # "Where does X go" decision tree + SoT hierarchy
├── CONTRIBUTING.md                    # Commit lane rules, PR policy, frontmatter schema, ID scheme
├── CLAUDE.md                          # Project instructions for Claude Code
├── .claude/
│   ├── skills/                        # Playbook/SOP library — single source of truth for agent workflows
│   └── agents/                        # Specialized subagents (tenant-manager, discovery-analyst, etc.)
├── .github/
│   └── workflows/
│       ├── ci-per-commit.yml          # Tier 1: validation + light regeneration on every push
│       ├── rollups-hourly.yml         # Tier 2: time rollups, cron @ :15 every hour
│       ├── staleness-daily.yml        # Tier 3: staleness + heavy reports, cron nightly
│       └── airia-sync.yml             # Tier 3: drift detection, cron nightly 03:00 ET
├── crm/
│   ├── contacts/
│   │   └── _template.md
│   ├── companies/
│   │   └── _template.md
│   ├── deals/
│   │   └── _template.md
│   └── pipeline.md                    # Sales pipeline stages (distinct from Airia "agents")
├── tasks/
│   ├── open/
│   ├── done/
│   └── README.md
├── projects/                          # Internal initiatives and cross-client efforts
│   ├── _template/
│   └── <slug>/
├── clients/                           # Active client engagements (target shape; see §6.1 for migration)
│   ├── _template/
│   └── <slug>/
│       ├── profile.md                 # Engagement scope, retainer terms, pillar mix
│       ├── iac/                       # Declarative config for this client's configured systems
│       │   └── airia/
│       │       ├── config.yaml
│       │       └── tenant.yaml
│       ├── mcps/                      # Per-client MCP integrations (one folder per MCP)
│       │   ├── _template/             # Scaffolds from mcps/<slug>/ with inheritance
│       │   ├── sharepoint/
│       │   │   ├── README.md          # Status, auth choice, overrides, blockers for THIS client
│       │   │   ├── config.md          # Client-specific config (tenant IDs, scopes selected)
│       │   │   └── validation.md      # Client-specific validation runs (refs library tests)
│       │   └── outlook/
│       ├── mcp-status.md              # Client × MCP status matrix (this client's row)
│       ├── strategy/                  # Discovery artifacts
│       ├── use-cases/                 # Per-use-case enrichment (lifecycle state lives in Airia)
│       ├── deliverables/              # Client-facing documents by pillar
│       ├── onboarding-log.md          # Timestamped state changes, sign-offs
│       └── reports/                   # Generated weekly reports + MBRs (committed)
├── systems/                           # NTEK-side platforms we operate in (cross-client)
│   ├── _template/
│   ├── airia/
│   ├── easycc/
│   ├── github/
│   ├── 1password/
│   ├── stripe/
│   ├── pandadoc/
│   ├── outlook/
│   ├── resend/
│   └── calendly/
├── mcps/                              # MCP-type records — platform-level knowledge per MCP type
│   ├── _template/
│   ├── sharepoint/
│   │   ├── README.md                  # Overview, version tracking, upstream changelog notes
│   │   ├── auth.md                    # Auth models, scopes (required + optional), scope selection guidance
│   │   ├── tools.md                   # Full tool inventory with descriptions and usage notes
│   │   ├── gotchas.md                 # Platform-level known issues, workarounds, edge cases
│   │   ├── validation.md              # Reusable validation test templates per tool
│   │   └── best-practices.md          # Patterns learned across deployments
│   ├── outlook/
│   ├── stripe-mcp/
│   ├── pandadoc-mcp/
│   └── 1password-mcp/
├── time/
│   ├── YYYY-MM/
│   │   └── <client>.md
│   └── README.md                      # Schema, pillar enum, conventions
├── use-cases/
│   └── library/                       # Reusable cross-client use case patterns
├── sops/
│   ├── onboarding.md
│   ├── mcp-integration.md             # References mcps/ library records
│   ├── admin-cred-handling.md
│   ├── use-case-lifecycle.md
│   └── notifications.md
├── email/
│   ├── templates/
│   ├── automations/
│   │   └── triggers.md
│   └── README.md
├── iac/                               # NTEK-level IaC (not client-specific)
│   ├── gateway-templates/
│   └── easycc-scaffolds/
├── index/
│   ├── README.md
│   ├── systems-and-mcps.md            # The two-layer MCP model and system/MCP distinction
│   ├── crm.md
│   ├── tasks.md
│   ├── time.md
│   ├── sharepoint.md
│   ├── outlook.md
│   ├── resend.md
│   ├── calendly.md
│   ├── pandadoc.md
│   ├── stripe.md
│   ├── 1password.md
│   ├── sites.md
│   ├── vendors.md
│   └── integrations.md
├── agent/
│   ├── briefings/
│   └── capture/
├── scripts/
│   ├── new-contact.sh
│   ├── new-company.sh
│   ├── new-deal.sh
│   ├── new-task.sh
│   ├── new-project.sh
│   ├── new-mcp-type.sh                # Scaffold an MCP-type record in mcps/
│   └── new-client-mcp.sh              # Scaffold a per-client MCP, inheriting from mcps/<slug>/
├── _generated/
│   ├── contacts.csv
│   ├── contacts.json
│   ├── pipeline-dashboard.md
│   ├── client-mcp-matrix.md           # Aggregated client × MCP status
│   ├── staleness-report.md
│   ├── time-by-client-YYYY-MM.md
│   ├── time-by-pillar-YYYY-MM.md
│   ├── retainer-status-YYYY-MM.md
│   └── airia-drift-YYYY-MM-DD.md
└── docs/
    ├── prd/
    ├── decisions/
    ├── architecture/
    └── templates/                     # Reusable deliverable templates by pillar

6.1 tenants/clients/ migration (deferred)

The existing tenants/ directory stays operational during v1. The target shape is clients/<slug>/ per §6. Cutover happens once the target structure is proven out with Tegre as the pilot (see §15 step 9) and the Airia sync workflow has run cleanly for two weeks.

Existing (tenants/<n>/)Target (clients/<n>/)
config.yamliac/airia/config.yaml
tenant.yamliac/airia/tenant.yaml
.env1Password item airia-<n> (see §10.1)
strategy/strategy/
use-cases/use-cases/
deliverables/deliverables/
reports/reports/ (committed)

New profile.md, mcp-status.md, mcps/ subdirectories, onboarding-log.md, and iac/ subdirs for non-Airia systems are authored fresh during migration.

7. Data Model

7.1 Core principle: contacts / companies / clients are distinct

Three separate concerns, three separate record types.

Contacts are stable people. Companies are relationships. Clients are engagements. A contact belongs to a company for their employment tenure. A company moves through relationship stages over its lifetime. An engagement exists only while active and is archived when it ends.

7.2 Second principle: MCPs have a shared type layer and a per-client layer

The MCP model is two-tier with explicit inheritance. This is the mechanism that makes onboarding the Nth client cheaper than the first.

MCP-type record (mcps/<slug>/) holds everything that’s true about the MCP independent of any client deployment:

Every client onboarding writes to the MCP-type record unless the lesson is genuinely client-specific. This is how the library compounds.

Per-client MCP record (clients/<slug>/mcps/<mcp-slug>/) holds only what’s specific to that client:

Rule for where a lesson lives: if it’s about the MCP platform (auth quirks, scope behavior, tool edge cases, version issues), it belongs in mcps/<slug>/. If it’s about this specific client’s environment or choices, it belongs in clients/<n>/mcps/<slug>/. When unsure, default to the library — it’s easier to demote later than to promote learnings scattered across client folders.

7.3 ID scheme

Every record carries a stable, prefix-scoped ID in frontmatter:

Time entries are embedded in monthly log files and are not individually addressable.

Cross-references use @<id> syntax inline. IDs must never change — if a record must be renamed, add an alias in frontmatter rather than reissuing.

7.4 Frontmatter schema (every content record)

---
id: <stable_id>
title: <string>
owner: <ben|matthew>
status: draft | published | stale | archived
last_verified: YYYY-MM-DD
criticality: low | medium | high | critical
pillar: strategy | governance | enablement | development | internal   # where applicable
tags: [<freeform>]
---

The pillar field applies to: projects, tasks, client profile.md (pillar mix), deliverables, time entries. Contacts, companies, deals, systems, and MCPs do not carry a pillar — they cross-cut.

Record-type-specific frontmatter extends this. Key examples:

MCP-type (mcps/sharepoint/README.md):

id: mcp_sharepoint
upstream_version: <mcp-server-version>
auth_models_supported: [admin_consent, user_delegated, hybrid]
tools_inventory_version: 2026-04-15

Per-client MCP (clients/tegre/mcps/sharepoint/README.md):

id: mcp_tegre_sharepoint
based_on: mcp_sharepoint
client: client_tegre
auth_model: admin_consent
status: not_started | admin_configured | user_authed | validated | live | broken
owner: ben
last_validated: YYYY-MM-DD
blocker: <optional text>

7.5 Lifecycle states

Use case lifecycle state is not managed here — it lives in Airia. The repo’s clients/<n>/use-cases/<n>.md carries enrichment; status comes from Airia at query time.

7.6 Client × MCP matrix

Each clients/<slug>/mcp-status.md contains a table with one row per MCP integration for that client. Columns:

CI generates _generated/client-mcp-matrix.md aggregating this across all clients.

7.7 Time entries

Time entries live in time/YYYY-MM/<client>.md. Each entry is a list item with inline YAML:

- date: 2026-04-20
  hours: 1.5
  pillar: governance
  client: tegre
  ref: @use_case_copilot_rollout
  note: "Reviewed guardrail config, drafted injection test cases"

Pillar enum (enforced globally):

Client slug must match a clients/<slug>/ directory or be _internal.

CI validates: pillar enum correctness, client slug existence, ref: target resolution, daily-sum sanity (flag >12h days), and missing-weekday warnings for active engagements.

7.8 Generated outputs and CI tiering

_generated/ is committed but never hand-edited. CI regenerates on three tiers based on how often the underlying data changes and how fresh consumers need it.

Tier 1 — Per-commit (.github/workflows/ci-per-commit.yml). Runs on every push to main and on PRs.

Target runtime: under 60 seconds.

Tier 2 — Hourly (.github/workflows/rollups-hourly.yml). Runs on cron at :15 every hour, plus workflow_dispatch.

Tier 3 — Daily (.github/workflows/staleness-daily.yml + airia-sync.yml). Runs on cron overnight.

Manual workflow_dispatch is enabled on Tier 2 and Tier 3 jobs so any rollup can be forced when needed.

8. Governance & Commit Lanes

8.1 Commit lanes

Operational commits → direct to main:

System commits → feature branch + PR:

The split between operational and system is reinforced by the two-layer MCP model: per-client status changes are operational; MCP-type library updates are system changes reviewed via PR. This is deliberate — library updates affect every future client onboarding.

8.2 Branch protection

8.3 Audit trail

Standard git history. No additional audit layer for v1. Revisit if Securo governance requires stronger attestation post-investment.

9. Capture & Notifications

9.1 Capture protocol

All capture is desktop-only via EasyCC and Claude Code slash commands (/track, /note, /task, etc.). Mobile capture deferred per §3.

9.2 Notification strategy

Two tiers:

Push-tier rules live in sops/notifications.md. Reviewed monthly to prevent alert fatigue.

10. Secrets Management

10.1 GitHub Actions integration

GitHub Actions use 1password/load-secrets-action@v2 backed by a 1Password Service Account scoped to the NTEK-Clients vault only. The service account token is the only secret stored in GitHub (OP_SA_TOKEN); all other secrets dereference at workflow runtime:

- uses: 1password/load-secrets-action@v2
  env:
    OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SA_TOKEN }}
    AIRIA_API_KEY: op://NTEK-Clients/airia-${{ matrix.client }}/api_key
    AIRIA_TENANT_ID: op://NTEK-Clients/airia-${{ matrix.client }}/tenant_id

Rotate the service account token yearly or on personnel change.

11. Agent Behavior (v1)

11.1 .claude/skills/ is the playbook library

All agent-executable workflows live in .claude/skills/<n>/SKILL.md. Single source of truth for agent procedures. EasyCC and Claude Code both execute skills against the same conventions.

Skill categories map to the Four Pillars plus cross-cutting ops:

PillarSkills
Strategy/discovery, /plan, /client-overview, /use-cases
Governance/guardrails, /governance, /redteam
Enablement/users, /gateway, /deliverables
Development/use-cases, /lifecycle, /run, /projects
Ops (cross-cutting)/status, /import, /diff, /onboard, /reports, /track, /pr, /ci-status, /lint, /new-client, /new-mcp-type, /new-client-mcp

The continuous learning system (.claude/skills/continuous-learning/) captures operational patterns as instincts from tool usage. Instincts graduate into formal skills via periodic evolve review.

11.2 Daily briefing agent

Runs locally via EasyCC, triggered on a schedule. Reads:

Produces:

11.3 Airia drift detection (GitHub Action)

.github/workflows/airia-sync.yml runs nightly (default 03:00 ET) and on manual dispatch:

  1. Matrix over clients/*/iac/airia/ (only clients with an Airia engagement)
  2. Load per-client creds from 1Password via the service account (§10.1)
  3. Execute python -m airia.cli diff <client>
  4. If diff non-empty:
  5. Write a summary to _generated/airia-drift-YYYY-MM-DD.md

Critical constraint: the action only flags resource config drift. It does not overwrite use case lifecycle state — Airia remains authoritative for AgentRequest status, and the repo’s use-cases/ enrichment is never touched by the sync.

11.4 Reports & MBRs

Weekly reports (/reports <client>): per-client HTML/PDF/EML generated from time/YYYY-MM/<client>.md, client use case activity (read from Airia), and delivered artifacts. Runs on Fridays. Output lands in clients/<n>/reports/weekly-YYYY-WW.{html,pdf,eml} — committed to git for historical auditability.

Monthly Business Reviews (/reports --mbr <client>): pillar-hour breakdown, use cases advanced, deliverables shipped, roadmap progress, retainer status with rollover math. Output lands in clients/<n>/reports/mbr-YYYY-MM.{html,pdf} — committed to git. Template in docs/templates/strategy/mbr.md.

Retainer rollover math is driven by profile.md frontmatter (retainer.contracted_hours, retainer.rollover_enabled, retainer.rollover_cap) and reads directly from the time log — no external dependency.

/reports --all generates reports across every active client in one pass.

Report file size is a known future concern; revisit at v1.5 if repo size becomes an issue.

11.5 Human-in-the-loop rules

11.6 MCP knowledge capture workflow

When an agent (or human) learns something during a client MCP onboarding, the classification step is explicit:

  1. Is this true about the MCP platform itself (auth quirk, scope behavior, tool edge case, version issue)? → write to mcps/<slug>/ via PR (system commit).
  2. Is this true only about this client (their environment, their IT policy, their specific config choice)? → write to clients/<n>/mcps/<slug>/ via direct commit (operational).
  3. If uncertain, default to the library. Easier to demote later than to spread a platform lesson across client folders.

Skills that run MCP onboarding (/onboard, /new-client-mcp) prompt explicitly for this classification at the end of each session.

12. Glossary

TermDefinition
Airia AgentA runnable AI pipeline in the Airia platform. Called “pipelines” in the Airia API and Python client code; called “agents” in all user-facing NTEK documentation. Code matches the API; docs match the mental model.
Agent RequestA use case record in Airia (AgentRequest API). Drives the use case lifecycle. Distinct from an Airia Agent.
PipelineIn this repo, refers exclusively to the CRM sales pipeline (crm/pipeline.md). Never used for Airia agents in NTEK-authored docs.
ClientA company with an active engagement, represented under clients/<slug>/. Not every company is a client.
CompanyAny organization NTEK tracks (prospect, active client, former client, partner, investor, vendor). Engagement state lives in relationship_type.
ContactA person. Stable across company changes.
DealA sales opportunity on the CRM pipeline, owned by a company.
ProjectAn internal initiative or cross-client effort, distinct from a client engagement. Lives under projects/.
Use caseA specific delivery work item within a client engagement. Enrichment in clients/<n>/use-cases/; lifecycle state in Airia.
SystemA platform NTEK operates in (Airia, EasyCC, GitHub, 1Password, Stripe, etc.). Cross-client. Lives in systems/.
MCP (type)The platform-level knowledge for an integration type, independent of any client. Lives in mcps/<slug>/. Compounds value over time as lessons are written back.
MCP (per-client)The specific deployment of an MCP for one client. Lives in clients/<n>/mcps/<slug>/ and references the MCP-type record via based_on.
PillarOne of the Four Pillars (Strategy, Governance, Enablement, Development) — activity categorization for time tracking, skills organization, and reporting. internal is a reserved pillar slug for non-billable NTEK work.

13. Open Questions (Deferred)

14. v1 Delivery Plan

Timeline: fast (no fixed date). Delivered in order. Each step is a committable unit; no step blocks the next — the repo is usable after step 1 and gets more valuable with each subsequent step.

  1. Repo constitution. README.md, CONTRIBUTING.md, CLAUDE.md. Covers: ID scheme, commit lanes, frontmatter schema, pillar enum, naming conventions, 1Password item naming, CI tiers.
  2. Templates. _template/ records for contacts, companies, deals, tasks, projects, clients, systems, MCP-types, per-client MCPs, use cases.
  3. Scaffolding scripts. new-contact.sh, new-company.sh, new-deal.sh, new-task.sh, new-project.sh, new-mcp-type.sh, new-client-mcp.sh.
  4. CI Tier 1. Frontmatter validation, ID uniqueness, @<id> resolution, link check, light _generated/ regeneration.
  5. CI Tier 2 and 3. Hourly rollups, nightly staleness, nightly Airia drift. Wired but running against empty matrices until later steps populate data.
  6. Index files. Thin initial versions for every system in the stack.
  7. 1Password Business provisioned. Vaults created. Service account generated. OP_SA_TOKEN stored as the sole GitHub repo secret. Airia client creds migrated from existing tenants/*/.env files.
  8. CRM migration. Existing contacts and companies populated. First company records for Tegre and Securo. Active deals populated.
  9. First MCP-type records. SharePoint, Outlook, and any other MCP currently in active use get their library records populated from existing knowledge.
  10. First client record (Tegre) as pilot. clients/tegre/ built in target shape, including mcps/ subdirectories that reference the library records from step 9.
  11. Systems records. Core platform records populated: Airia, EasyCC, GitHub, 1Password, Stripe.
  12. Airia IaC folded. clients/tegre/iac/airia/ populated from existing Tegre config.
  13. Airia sync workflow live. Matrix initially runs against Tegre only; verify drift detection and critical-drift push-notification behavior. Then extend matrix to all clients.
  14. Time tracking schema. time/README.md + pillar enum + entry format. Rewrite /track skill. Harvest backfill handled manually.
  15. Reports rewrite. /reports reads from time/ instead of the Harvest API. Retainer rollover logic ported. Verify Tegre rollover math matches prior output for the last three months.
  16. MBR generator. /reports --mbr implemented. Template in docs/templates/strategy/mbr.md. First MBR generated for Tegre as acceptance test.
  17. Push notifications. Pushover (or equivalent) wired. Push-tier rules authored in sops/notifications.md.
  18. Daily briefing agent. EasyCC reads repo + Outlook + Calendly + Stripe + PandaDoc + Airia notetaker. First two weeks of briefings generated; adjust based on what surfaces.
  19. Tenants cutover. Once Tegre client record is proven out and Airia sync has run cleanly for two weeks, migrate remaining tenants/* to clients/*. Remove legacy tenants/ directory.

15. Review Cadence