pace-engine 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: pace-engine
3
+ Version: 0.1.0
4
+ Summary: PACE - an engineering operating system: a versioned, installable engine that preserves and governs a project's knowledge so any AI understands it in seconds.
5
+ Author: Cley Duarte
6
+ Project-URL: Homepage, https://github.com/cleyduartees-dot/PACE
7
+ Keywords: ai,knowledge,engineering,governance,memory,context
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+
11
+ # PACE
12
+
13
+ An engineering operating system: a versioned, installable engine that preserves, organizes, governs and evolves the architectural knowledge of software projects, in collaboration between people and AI.
14
+
15
+ PACE is not a library embedded inside a product. It is installed once and governs any number of independent projects, each carrying only its own `.pace/` memory — never a copy of PACE itself.
16
+
17
+ ## Status
18
+
19
+ Founded 2026-07-06. This repository currently contains only this founding commit. The minimal day-1 skeleton (kernel, services, engines, ontology, protocols, governance, policies, standards, contracts, cli, history, docs) is the next step, not yet built.
20
+
21
+ ## Founding principle
22
+
23
+ - **PACE** — the engine. Code only, versioned, installable. No knowledge of any specific organization or project.
24
+ - **Organización** — an adopting company's own governance memory (who holds authority, its own policies, its registry of projects), same recursive shape as a project instance, scoped one level up.
25
+ - **Instancia (`.pace/`)** — a single project's own memory: mission, vision, roadmap, sprint, handoff, history, decisions.
26
+ - **Proyecto** — the actual product codebase. Outside PACE's concern beyond hosting a `.pace/` folder at its root.
27
+
28
+ ## Roadmap (founding sequence)
29
+
30
+ 1. Crear el repositorio oficial PACE. — done
31
+ 2. Implementar el esqueleto mínimo.
32
+ 3. Implementar `pace init`.
33
+ 4. Adoptar el primer proyecto gobernado por PACE.
34
+ 5. Implementar `pace create`.
35
+ 6. Crear el primer proyecto nuevo nacido desde PACE.
@@ -0,0 +1,25 @@
1
+ # PACE
2
+
3
+ An engineering operating system: a versioned, installable engine that preserves, organizes, governs and evolves the architectural knowledge of software projects, in collaboration between people and AI.
4
+
5
+ PACE is not a library embedded inside a product. It is installed once and governs any number of independent projects, each carrying only its own `.pace/` memory — never a copy of PACE itself.
6
+
7
+ ## Status
8
+
9
+ Founded 2026-07-06. This repository currently contains only this founding commit. The minimal day-1 skeleton (kernel, services, engines, ontology, protocols, governance, policies, standards, contracts, cli, history, docs) is the next step, not yet built.
10
+
11
+ ## Founding principle
12
+
13
+ - **PACE** — the engine. Code only, versioned, installable. No knowledge of any specific organization or project.
14
+ - **Organización** — an adopting company's own governance memory (who holds authority, its own policies, its registry of projects), same recursive shape as a project instance, scoped one level up.
15
+ - **Instancia (`.pace/`)** — a single project's own memory: mission, vision, roadmap, sprint, handoff, history, decisions.
16
+ - **Proyecto** — the actual product codebase. Outside PACE's concern beyond hosting a `.pace/` folder at its root.
17
+
18
+ ## Roadmap (founding sequence)
19
+
20
+ 1. Crear el repositorio oficial PACE. — done
21
+ 2. Implementar el esqueleto mínimo.
22
+ 3. Implementar `pace init`.
23
+ 4. Adoptar el primer proyecto gobernado por PACE.
24
+ 5. Implementar `pace create`.
25
+ 6. Crear el primer proyecto nuevo nacido desde PACE.
File without changes
File without changes
@@ -0,0 +1,253 @@
1
+ """PACE CLI - thin command layer delegating to the Kernel and Engines.
2
+
3
+ Beyond argument handling, the only logic here is the guided intake: an
4
+ interactive setup that seeds a project's memory from the owner's answers.
5
+ Run as `python cli/pace.py <command> ...`, or install and run `pace ...`.
6
+ """
7
+
8
+ import argparse
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
13
+ from pace.kernel.kernel import locate_instance, validate_instance
14
+ from pace.services.pdl import read_pdl
15
+ from pace.engines.project_creator import init_instance, create_project
16
+ from pace.engines.handoff import generate_handoff
17
+ from pace.engines.memory import remember, recall
18
+
19
+ ACTIVE_SECTIONS = [
20
+ ("MISSION", "ACTIVE_MISSION"),
21
+ ("VISION", "ACTIVE_VISION"),
22
+ ("ROADMAP", "ACTIVE_ROADMAP"),
23
+ ("SPRINT", "ACTIVE_SPRINT"),
24
+ ]
25
+
26
+
27
+ def cmd_doctor(args) -> int:
28
+ root = locate_instance(Path(args.path) if args.path else None)
29
+ if root is None:
30
+ print("no .pace/ instance found")
31
+ return 1
32
+ violations = validate_instance(root)
33
+ if violations:
34
+ print(f"INVALID - {len(violations)} violation(s):")
35
+ for v in violations:
36
+ print(f" - {v}")
37
+ return 1
38
+ print(f"VALID - {root}")
39
+ return 0
40
+
41
+
42
+ def cmd_context(args) -> int:
43
+ root = locate_instance(Path(args.path) if args.path else None)
44
+ if root is None:
45
+ print("no .pace/ instance found")
46
+ return 1
47
+
48
+ instance = read_pdl(root / "INSTANCE.pdl")
49
+ active = read_pdl(root / "ACTIVE_VERSIONS.pdl")
50
+
51
+ print(f"NAME {instance.get('NAME')}")
52
+ print(f"SLUG {instance.get('SLUG')}")
53
+ print(f"KIND {instance.get('KIND')}")
54
+ print(f"SCHEMA_VERSION {instance.get('SCHEMA_VERSION')}")
55
+ if instance.get("ORG_REF"):
56
+ print(f"ORG_REF {instance.get('ORG_REF')}")
57
+ print()
58
+
59
+ for label, key in ACTIVE_SECTIONS:
60
+ relative_path = active.get(key)
61
+ if not relative_path:
62
+ continue
63
+ full_path = root / relative_path
64
+ print(f"--- {label} ({relative_path}) ---")
65
+ if full_path.is_file():
66
+ print(full_path.read_text(encoding="utf-8").strip())
67
+ else:
68
+ print("(file not found)")
69
+ print()
70
+ return 0
71
+
72
+
73
+ def _slugify(name: str) -> str:
74
+ slug = "".join(c if c.isalnum() else "-" for c in name.lower())
75
+ while "--" in slug:
76
+ slug = slug.replace("--", "-")
77
+ return slug.strip("-") or "project"
78
+
79
+
80
+ def _prompt(text: str, default: str = "") -> str:
81
+ suffix = f" [{default}]" if default else ""
82
+ try:
83
+ value = input(f"{text}{suffix}\n> ").strip()
84
+ except EOFError:
85
+ value = ""
86
+ return value or default
87
+
88
+
89
+ def run_guided_intake(kind, name, slug, org_ref):
90
+ """Interactive setup: ask a few questions and seed mission / vision /
91
+ roadmap / sprint. The AI (or the owner) answers; nothing is invented.
92
+ Returns the resolved identity plus an `extra` dict of seeded content."""
93
+ print("\nPACE guided setup - a few questions to seed your project's memory.")
94
+ print("Press Enter to accept a [default] or to skip a question.\n")
95
+
96
+ if not name:
97
+ name = _prompt("Project name") or "Unnamed project"
98
+ kind_in = _prompt("Kind (PROJECT / ORGANIZATION)", kind or "PROJECT").upper()
99
+ kind = "ORGANIZATION" if kind_in.startswith("O") else "PROJECT"
100
+ if kind == "PROJECT" and not org_ref:
101
+ org_ref = _prompt("Organization it belongs to (org ref)") or "org"
102
+ if not slug:
103
+ slug = _prompt("Slug", _slugify(name))
104
+
105
+ extra = {}
106
+ mission = _prompt("Why does this project exist? (mission)")
107
+ if mission:
108
+ extra["mission"] = mission
109
+ vision = _prompt("Where is it going? (vision)")
110
+ if vision:
111
+ extra["vision"] = vision
112
+ roadmap = _prompt("What is pending? (roadmap - main items)")
113
+ if roadmap:
114
+ extra["roadmap"] = roadmap
115
+ sprint = _prompt("What are you working on right now? (current sprint)")
116
+ if sprint:
117
+ extra["sprint"] = sprint
118
+ return kind, name, slug, org_ref, extra
119
+
120
+
121
+ def cmd_init(args) -> int:
122
+ kind, name, slug, org_ref = args.kind, args.name, args.slug, args.org_ref
123
+ extra = {}
124
+ if args.guided:
125
+ kind, name, slug, org_ref, extra = run_guided_intake(kind, name, slug, org_ref)
126
+
127
+ if not name:
128
+ print("init failed: --name is required (or use --guided)")
129
+ return 1
130
+ if not slug:
131
+ slug = _slugify(name)
132
+
133
+ try:
134
+ root = init_instance(
135
+ Path(args.path), kind=kind, name=name, slug=slug, org_ref=org_ref, **extra
136
+ )
137
+ except (FileExistsError, ValueError) as error:
138
+ print(f"init failed: {error}")
139
+ return 1
140
+ print(f"created .pace/ at {root}")
141
+ violations = validate_instance(root)
142
+ if violations:
143
+ print("WARNING - the new instance is not structurally valid:")
144
+ for v in violations:
145
+ print(f" - {v}")
146
+ return 1
147
+ return 0
148
+
149
+
150
+ def cmd_create(args) -> int:
151
+ try:
152
+ root = create_project(
153
+ Path(args.path),
154
+ name=args.name,
155
+ slug=args.slug,
156
+ org_ref=args.org_ref,
157
+ )
158
+ except FileExistsError as error:
159
+ print(f"create failed: {error}")
160
+ return 1
161
+ print(f"created project at {root.parent}")
162
+ violations = validate_instance(root)
163
+ if violations:
164
+ print("WARNING - the new instance is not structurally valid:")
165
+ for v in violations:
166
+ print(f" - {v}")
167
+ return 1
168
+ return 0
169
+
170
+
171
+ def cmd_handoff(args) -> int:
172
+ root = locate_instance(Path(args.path) if args.path else None)
173
+ if root is None:
174
+ print("no .pace/ instance found")
175
+ return 1
176
+ out = generate_handoff(root)
177
+ print(f"handoff regenerated at {out}\n")
178
+ print(out.read_text(encoding="utf-8"))
179
+ return 0
180
+
181
+
182
+ def cmd_remember(args) -> int:
183
+ root = locate_instance(Path(args.path) if args.path else None)
184
+ if root is None:
185
+ print("no .pace/ instance found")
186
+ return 1
187
+ out = remember(root, args.text)
188
+ print(f"remembered in {out}")
189
+ return 0
190
+
191
+
192
+ def cmd_recall(args) -> int:
193
+ root = locate_instance(Path(args.path) if args.path else None)
194
+ if root is None:
195
+ print("no .pace/ instance found")
196
+ return 1
197
+ print(recall(root))
198
+ return 0
199
+
200
+
201
+ def build_parser() -> argparse.ArgumentParser:
202
+ parser = argparse.ArgumentParser(prog="pace")
203
+ subparsers = parser.add_subparsers(dest="command", required=True)
204
+
205
+ doctor = subparsers.add_parser("doctor", help="validate a .pace/ instance structurally")
206
+ doctor.add_argument("path", nargs="?", default=None)
207
+ doctor.set_defaults(func=cmd_doctor)
208
+
209
+ context = subparsers.add_parser("context", help="print a .pace/ instance's current context")
210
+ context.add_argument("path", nargs="?", default=None)
211
+ context.set_defaults(func=cmd_context)
212
+
213
+ init = subparsers.add_parser("init", help="create a new .pace/ instance in an existing project")
214
+ init.add_argument("path")
215
+ init.add_argument("--kind", choices=["PROJECT", "ORGANIZATION"], default="PROJECT")
216
+ init.add_argument("--name", default=None)
217
+ init.add_argument("--slug", default=None)
218
+ init.add_argument("--org-ref", dest="org_ref", default=None)
219
+ init.add_argument("--guided", action="store_true",
220
+ help="interactive guided setup that seeds mission/vision/roadmap/sprint")
221
+ init.set_defaults(func=cmd_init)
222
+
223
+ handoff = subparsers.add_parser("handoff", help="regenerate the AI-onboarding handoff for a .pace/ instance")
224
+ handoff.add_argument("path", nargs="?", default=None)
225
+ handoff.set_defaults(func=cmd_handoff)
226
+
227
+ remember = subparsers.add_parser("remember", help="append a continuity note to the project's working memory")
228
+ remember.add_argument("text")
229
+ remember.add_argument("path", nargs="?", default=None)
230
+ remember.set_defaults(func=cmd_remember)
231
+
232
+ recall = subparsers.add_parser("recall", help="print the project's working/continuity memory")
233
+ recall.add_argument("path", nargs="?", default=None)
234
+ recall.set_defaults(func=cmd_recall)
235
+
236
+ create = subparsers.add_parser("create", help="generate a brand-new project governed by PACE from scratch")
237
+ create.add_argument("path")
238
+ create.add_argument("--name", required=True)
239
+ create.add_argument("--slug", required=True)
240
+ create.add_argument("--org-ref", dest="org_ref", required=True)
241
+ create.set_defaults(func=cmd_create)
242
+
243
+ return parser
244
+
245
+
246
+ def main(argv=None) -> int:
247
+ parser = build_parser()
248
+ args = parser.parse_args(argv)
249
+ return args.func(args)
250
+
251
+
252
+ if __name__ == "__main__":
253
+ raise SystemExit(main())
@@ -0,0 +1,139 @@
1
+ CONTRACT_VERSION 0.1.0
2
+
3
+ STATUS DRAFT
4
+
5
+ OWNER President Cley Duarte
6
+
7
+ DEPENDS_ON
8
+
9
+ ontology/PACE_ONTOLOGY_0.1.0.pdl
10
+ protocols/PDL_SPECIFICATION.pdl (not yet written — referenced for future
11
+ format validation, not required for this contract to be a valid design
12
+ artifact today)
13
+
14
+ PURPOSE
15
+
16
+ Define the physical, checkable shape any .pace/ instance (a project or an
17
+ organization hub — same KIND distinction, not two different contracts)
18
+ must have to be valid. This is the representation layer for the entities,
19
+ relations and assertions defined in PACE_ONTOLOGY_0.1.0.
20
+
21
+ ROOT_MANIFEST
22
+
23
+ .pace/INSTANCE.pdl
24
+
25
+ REPRESENTS the GOVERNED_UNIT entity itself and its direct identity
26
+ assertions and relations.
27
+
28
+ REQUIRED_FIELDS
29
+ KIND PROJECT | ORGANIZATION
30
+ NAME (HAS_NAME)
31
+ SLUG (HAS_SLUG)
32
+ SCHEMA_VERSION (HAS_SCHEMA_VERSION — which Contract version this
33
+ instance claims to satisfy)
34
+ PACE_VERSION (HAS_PACE_VERSION — which PACE engine version
35
+ created or last managed this instance. Traceability
36
+ only, permanently: the Kernel never decides what it
37
+ can open based on this field, only on SCHEMA_VERSION
38
+ — the same way a browser interprets HTML by its
39
+ declared version, not by which browser authored it)
40
+ ORG_REF (BELONGS_TO target — required if KIND=PROJECT,
41
+ absent if KIND=ORGANIZATION)
42
+ CREATED_AT (HAS_CREATED_AT)
43
+
44
+ .pace/ACTIVE_VERSIONS.pdl
45
+
46
+ REPRESENTS the IS_CURRENTLY_ACTIVE relation, one entry per versioned
47
+ assertion sequence.
48
+
49
+ REQUIRED_FIELDS
50
+ ACTIVE_MISSION
51
+ ACTIVE_VISION
52
+ ACTIVE_ROADMAP
53
+ ACTIVE_SPRINT
54
+
55
+ SECTIONS
56
+
57
+ mission/, vision/, roadmap/, sprint/
58
+ REPRESENTS HAS_MISSION / HAS_VISION / HAS_ROADMAP / HAS_CURRENT_SPRINT
59
+ FORMAT PDL
60
+ MUTABILITY PROTECTED — superseded, never edited in place; every prior
61
+ version file is kept
62
+ REQUIRED_AT_V0.1 folder must exist; content optional
63
+
64
+ history/
65
+ REPRESENTS HISTORY_ENTRY
66
+ FORMAT PDL
67
+ MUTABILITY PROTECTED — append-only
68
+ REQUIRED_AT_V0.1 must exist, with at least one founding entry
69
+
70
+ releases/
71
+ REPRESENTS RELEASE
72
+ FORMAT PDL
73
+ MUTABILITY PROTECTED — append-only
74
+ REQUIRED_AT_V0.1 folder must exist; content optional
75
+
76
+ decisions/
77
+ REPRESENTS DECISION
78
+ FORMAT PDL (by explicit decision — consistency over the old system's
79
+ mixed Markdown/PDL convention for this kind of record)
80
+ MUTABILITY PROTECTED — append-only
81
+ REQUIRED_AT_V0.1 folder must exist; content optional
82
+
83
+ requests/
84
+ REPRESENTS REQUEST
85
+ FORMAT PDL
86
+ MUTABILITY core fields (WHO, DATE, RAW_TEXT) PROTECTED, immutable once
87
+ logged. STATUS and PROMOTED_TO are the one explicit exception —
88
+ updatable as the request's lifecycle advances.
89
+ REQUIRED_AT_V0.1 folder must exist; content optional
90
+
91
+ handoff/
92
+ REPRESENTS no new entity, relation or assertion — a pure representation
93
+ layer: a materialized view over mission/vision/roadmap/sprint and
94
+ ACTIVE_VERSIONS, built for AI-onboarding consumption.
95
+ FORMAT PDL
96
+ MUTABILITY REGENERABLE — fully disposable, rebuilt by the Bootstrap /
97
+ Handoff engine (not yet built)
98
+ REQUIRED_AT_V0.1 folder must exist, empty until that engine ships
99
+
100
+ memory/generated/
101
+ REPRESENTS computed reports (audits, continuity scores) — a regenerable
102
+ view, not an entity of its own
103
+ FORMAT JSON
104
+ MUTABILITY REGENERABLE — free to overwrite or discard
105
+ REQUIRED_AT_V0.1 folder must exist; content optional
106
+
107
+ memory/persistent/
108
+ REPRESENTS HAS_CONTINUITY_NOTE
109
+ FORMAT PDL or JSON
110
+ MUTABILITY PROTECTED — refined in place, never silently discarded
111
+ REQUIRED_AT_V0.1 folder must exist; content optional
112
+
113
+ NOT_REPRESENTED_HERE
114
+
115
+ ACTOR entities are not defined per project instance. They live at the
116
+ organization's own governed-unit instance and are referenced by ID from
117
+ any assertion's ASSERTED_BY / APPROVED_BY field — this avoids duplicating
118
+ "who is the President" inside every project instance.
119
+
120
+ The DEPENDS_ON relation, as used for the PACE repository's own 12-component
121
+ build graph, is not represented inside a project instance. It belongs to
122
+ PACE's own repository, not to any .pace/ instance.
123
+
124
+ HARD_RULES
125
+
126
+ 1 Every REQUIRED_AT_V0.1 folder must exist structurally, even empty,
127
+ from the moment pace init runs. Empty is valid; missing is not.
128
+
129
+ 2 No code, script or executable file of any kind may exist anywhere
130
+ inside .pace/, in any section, ever.
131
+
132
+ 3 PROTECTED sections are never edited in place. Any change to the
133
+ content of an existing file is a contract violation — only new files
134
+ or new versions are allowed.
135
+
136
+ 4 REGENERABLE sections (handoff/, memory/generated/) may be freely
137
+ rewritten or deleted at any time without violating this contract.
138
+
139
+ END
File without changes
File without changes
@@ -0,0 +1,113 @@
1
+ """Handoff engine - regenerates the AI-onboarding view of a .pace/ instance.
2
+
3
+ Produces .pace/handoff/HANDOFF.md: the single file an AI reads first. It
4
+ names who governs the project (whom to consult), how to work here, and the
5
+ current mission / vision / roadmap / sprint, plus pointers to the deeper
6
+ memory. The handoff/ section is REGENERABLE: this rebuilds it from the
7
+ authoritative sources, never the other way around.
8
+ """
9
+
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
14
+ from pace.services.pdl import read_pdl
15
+
16
+ ACTIVE_SECTIONS = [
17
+ ("Mission", "ACTIVE_MISSION"),
18
+ ("Vision", "ACTIVE_VISION"),
19
+ ("Roadmap", "ACTIVE_ROADMAP"),
20
+ ("Current sprint", "ACTIVE_SPRINT"),
21
+ ]
22
+
23
+
24
+ def _read_section(root: Path, relative_path):
25
+ if not relative_path:
26
+ return "(not set)"
27
+ full = root / relative_path
28
+ if not full.is_file():
29
+ return "(file not found)"
30
+ return full.read_text(encoding="utf-8").strip()
31
+
32
+
33
+ def _count_pdl(root: Path, section: str) -> int:
34
+ d = root / section
35
+ if not d.is_dir():
36
+ return 0
37
+ return sum(1 for p in d.iterdir() if p.is_file() and p.suffix == ".pdl")
38
+
39
+
40
+ def _root_authority(root: Path):
41
+ actors_dir = Path(root) / "actors"
42
+ if not actors_dir.is_dir():
43
+ return None
44
+ for p in sorted(actors_dir.glob("*.pdl")):
45
+ data = read_pdl(p)
46
+ if str(data.get("IS_ROOT_AUTHORITY", "")).strip().lower() == "true":
47
+ label = f"{data.get('ROLE', '')} {data.get('NAME', '')}".strip()
48
+ return label or data.get("NAME")
49
+ return None
50
+
51
+
52
+ def generate_handoff(root: Path) -> Path:
53
+ """Rebuild .pace/handoff/HANDOFF.md from the instance. Returns its path."""
54
+ root = Path(root)
55
+ instance = read_pdl(root / "INSTANCE.pdl")
56
+ active = read_pdl(root / "ACTIVE_VERSIONS.pdl")
57
+ name = instance.get("NAME", "this project")
58
+ kind = instance.get("KIND", "PROJECT")
59
+ authority = _root_authority(root)
60
+
61
+ out = []
62
+ out.append(f"# PACE Handoff - {name}")
63
+ out.append("")
64
+ out.append("You are an AI joining this project. Read this first: it is the")
65
+ out.append("project's own memory, so you do not have to ask what we are doing")
66
+ out.append("or why. This file is regenerated by PACE - do not edit it by hand.")
67
+ out.append("")
68
+ out.append("## How to work here")
69
+ out.append("")
70
+ if authority:
71
+ out.append(f"- The ROOT_AUTHORITY of this project is **{authority}**.")
72
+ out.append(" You ADVISE and AUDIT; they decide. Propose to them, never")
73
+ out.append(" override. Confirm before anything becomes official.")
74
+ else:
75
+ out.append("- You ADVISE and AUDIT; the project owner (ROOT_AUTHORITY) decides.")
76
+ out.append(" Propose, never override. Confirm with the owner first.")
77
+ out.append("- Every permanent correction is logged as a request and, once")
78
+ out.append(" approved, becomes a rule you must follow. Do not re-ask what an")
79
+ out.append(" approved rule already settles.")
80
+ out.append("")
81
+ out.append("## Identity")
82
+ out.append("")
83
+ out.append(f"- Name: {name}")
84
+ out.append(f"- Kind: {kind}")
85
+ if instance.get("ORG_REF"):
86
+ out.append(f"- Belongs to: {instance.get('ORG_REF')}")
87
+ if authority:
88
+ out.append(f"- Root authority: {authority}")
89
+ out.append("")
90
+
91
+ for label, key in ACTIVE_SECTIONS:
92
+ out.append(f"## {label}")
93
+ out.append("")
94
+ out.append("```")
95
+ out.append(_read_section(root, active.get(key)))
96
+ out.append("```")
97
+ out.append("")
98
+
99
+ out.append("## Where the rest of the memory lives")
100
+ out.append("")
101
+ out.append(f"- Decisions: .pace/decisions/ ({_count_pdl(root, 'decisions')} recorded)")
102
+ out.append(f"- History: .pace/history/ ({_count_pdl(root, 'history')} entries)")
103
+ out.append(f"- Requests: .pace/requests/ ({_count_pdl(root, 'requests')} logged in intake)")
104
+ out.append("")
105
+ out.append("Read those for the WHY behind decisions and the reasoning that is")
106
+ out.append("not in the code - including paths that were tried and discarded.")
107
+ out.append("")
108
+
109
+ handoff_dir = root / "handoff"
110
+ handoff_dir.mkdir(parents=True, exist_ok=True)
111
+ path = handoff_dir / "HANDOFF.md"
112
+ path.write_text("\n".join(out) + "\n", encoding="utf-8")
113
+ return path
@@ -0,0 +1,43 @@
1
+ """Working-memory engine - the continuity notes an AI keeps so it does not
2
+ lose the thread within a long chat or across chats (the anti-"dementia"
3
+ layer). `remember` appends a note; `recall` prints the accumulated memory.
4
+
5
+ Lives in .pace/memory/persistent/CONTINUITY.md - refined in place, never
6
+ silently discarded (HAS_CONTINUITY_NOTE). Agreements that become permanent
7
+ graduate from here into decisions/ or history/; this file is the running
8
+ working memory, not the system of record.
9
+ """
10
+
11
+ from datetime import datetime, timezone
12
+ from pathlib import Path
13
+
14
+ MEMORY_FILE = "memory/persistent/CONTINUITY.md"
15
+
16
+ _HEADER = (
17
+ "# Continuity memory\n\n"
18
+ "Running notes so an AI keeps the thread - objective, decisions, open\n"
19
+ "threads, latest state. Newest last. Read this every turn; do not lose\n"
20
+ "what was already agreed.\n\n"
21
+ )
22
+
23
+
24
+ def _memory_path(root: Path) -> Path:
25
+ return Path(root) / MEMORY_FILE
26
+
27
+
28
+ def remember(root: Path, text: str) -> Path:
29
+ path = _memory_path(root)
30
+ path.parent.mkdir(parents=True, exist_ok=True)
31
+ if not path.exists():
32
+ path.write_text(_HEADER, encoding="utf-8")
33
+ stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M")
34
+ with path.open("a", encoding="utf-8") as handle:
35
+ handle.write(f"- [{stamp}] {text}\n")
36
+ return path
37
+
38
+
39
+ def recall(root: Path) -> str:
40
+ path = _memory_path(root)
41
+ if not path.is_file():
42
+ return '(no continuity memory yet - add notes with: pace remember "...")'
43
+ return path.read_text(encoding="utf-8").strip()
@@ -0,0 +1,138 @@
1
+ """Project Creator engine — init and create modes.
2
+
3
+ init_instance() attaches a valid, structurally minimal .pace/ instance to
4
+ a project directory that already exists (its own code lives elsewhere,
5
+ untouched).
6
+
7
+ create_project() generates a brand-new project from scratch: a fresh
8
+ directory, a git repository, a minimal README, and a .pace/ instance —
9
+ nothing stack-specific (no framework, no language scaffolding). That is
10
+ a separate, later capability (templates/, not yet built), not part of
11
+ this minimal create mode.
12
+ """
13
+
14
+ import subprocess
15
+ import sys
16
+ from datetime import datetime, timezone
17
+ from pathlib import Path
18
+
19
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
20
+ from pace.services.contract_loader import load_instance_contract
21
+ from pace.services.version import PACE_VERSION
22
+
23
+ CONTRACT_PATH = Path(__file__).resolve().parent.parent / "contracts" / "INSTANCE_CONTRACT_0.1.0.pdl"
24
+ CONTRACT_VERSION = "0.1.0"
25
+
26
+ PLACEHOLDER = "Not yet defined."
27
+
28
+
29
+ def _write_pdl(path: Path, fields: dict) -> None:
30
+ lines = [f"{key} {value}".rstrip() for key, value in fields.items()]
31
+ lines.append("END")
32
+ path.parent.mkdir(parents=True, exist_ok=True)
33
+ path.write_text("\n".join(lines) + "\n", encoding="utf-8")
34
+
35
+
36
+ def init_instance(
37
+ target_dir: Path,
38
+ kind: str,
39
+ name: str,
40
+ slug: str,
41
+ org_ref: str = None,
42
+ mission: str = PLACEHOLDER,
43
+ vision: str = PLACEHOLDER,
44
+ roadmap: str = PLACEHOLDER,
45
+ sprint: str = PLACEHOLDER,
46
+ ) -> Path:
47
+ """Create a minimal, structurally valid .pace/ instance inside
48
+ `target_dir`. Raises if one already exists there."""
49
+ target_dir = Path(target_dir)
50
+ root = target_dir / ".pace"
51
+ if root.exists():
52
+ raise FileExistsError(f".pace/ already exists at {root}")
53
+
54
+ if kind == "PROJECT" and not org_ref:
55
+ raise ValueError("KIND=PROJECT requires org_ref")
56
+
57
+ contract = load_instance_contract(CONTRACT_PATH)
58
+
59
+ for section in sorted(contract["sections"]):
60
+ (root / section).mkdir(parents=True, exist_ok=True)
61
+
62
+ created_at = datetime.now(timezone.utc).isoformat()
63
+
64
+ instance_fields = {
65
+ "KIND": kind,
66
+ "NAME": name,
67
+ "SLUG": slug,
68
+ "SCHEMA_VERSION": CONTRACT_VERSION,
69
+ "PACE_VERSION": PACE_VERSION,
70
+ "CREATED_AT": created_at,
71
+ }
72
+ if org_ref:
73
+ instance_fields["ORG_REF"] = org_ref
74
+ _write_pdl(root / "INSTANCE.pdl", instance_fields)
75
+
76
+ _write_pdl(root / "mission" / "MISSION_1.0.0.pdl", {
77
+ "MISSION_VERSION": "1.0.0", "STATUS": "APPROVED", "MISSION": mission,
78
+ })
79
+ _write_pdl(root / "vision" / "VISION_1.0.0.pdl", {
80
+ "VISION_VERSION": "1.0.0", "STATUS": "APPROVED", "VISION": vision,
81
+ })
82
+ _write_pdl(root / "roadmap" / "ROADMAP_1.0.0.pdl", {
83
+ "ROADMAP_VERSION": "1.0.0", "STATUS": "APPROVED", "ROADMAP": roadmap,
84
+ })
85
+ _write_pdl(root / "sprint" / "SPRINT_1.pdl", {
86
+ "SPRINT_VERSION": "1", "STATUS": "ACTIVE", "SPRINT": sprint,
87
+ })
88
+
89
+ _write_pdl(root / "ACTIVE_VERSIONS.pdl", {
90
+ "ACTIVE_MISSION": "mission/MISSION_1.0.0.pdl",
91
+ "ACTIVE_VISION": "vision/VISION_1.0.0.pdl",
92
+ "ACTIVE_ROADMAP": "roadmap/ROADMAP_1.0.0.pdl",
93
+ "ACTIVE_SPRINT": "sprint/SPRINT_1.pdl",
94
+ })
95
+
96
+ _write_pdl(root / "history" / "HISTORY-0001-FOUNDING.pdl", {
97
+ "HISTORY_VERSION": "1.0.0",
98
+ "TYPE": "Founding",
99
+ "STATUS": "APPROVED",
100
+ "TITLE": f"{name} founded as a PACE-governed instance.",
101
+ })
102
+
103
+ return root
104
+
105
+
106
+ def create_project(
107
+ target_dir: Path,
108
+ name: str,
109
+ slug: str,
110
+ org_ref: str,
111
+ mission: str = PLACEHOLDER,
112
+ vision: str = PLACEHOLDER,
113
+ roadmap: str = PLACEHOLDER,
114
+ sprint: str = PLACEHOLDER,
115
+ ) -> Path:
116
+ """Generate a brand-new project from scratch: creates `target_dir`
117
+ (must not already exist or must be empty), initializes a git
118
+ repository, writes a minimal README, and attaches a .pace/ instance.
119
+ Stack-specific scaffolding is deliberately out of scope."""
120
+ target_dir = Path(target_dir)
121
+ if target_dir.exists() and any(target_dir.iterdir()):
122
+ raise FileExistsError(f"{target_dir} already exists and is not empty")
123
+ target_dir.mkdir(parents=True, exist_ok=True)
124
+
125
+ subprocess.run(
126
+ ["git", "init"], cwd=target_dir, check=True,
127
+ capture_output=True, text=True,
128
+ )
129
+
130
+ (target_dir / "README.md").write_text(
131
+ f"# {name}\n\nGoverned by PACE. See .pace/ for its mission, vision, roadmap and history.\n",
132
+ encoding="utf-8",
133
+ )
134
+
135
+ return init_instance(
136
+ target_dir, kind="PROJECT", name=name, slug=slug, org_ref=org_ref,
137
+ mission=mission, vision=vision, roadmap=roadmap, sprint=sprint,
138
+ )
File without changes
@@ -0,0 +1,105 @@
1
+ """PACE Kernel — locates a .pace/ instance and validates it structurally
2
+ against contracts/INSTANCE_CONTRACT_0.1.0.pdl, loaded at runtime from the
3
+ actual file, not a hand transcription of its rules.
4
+
5
+ Deliberately minimal: this is structural validation only (does the
6
+ required shape exist, is SCHEMA_VERSION supported). Deeper, semantic
7
+ validation belongs to the future Doctor engine, not the Kernel.
8
+ """
9
+
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
14
+ from pace.services.fs import find_upward
15
+ from pace.services.pdl import read_pdl
16
+ from pace.services.contract_loader import load_instance_contract
17
+ from pace.services.validate import (
18
+ require_fields,
19
+ require_dirs,
20
+ require_non_empty_dir,
21
+ forbid_file_suffixes,
22
+ )
23
+
24
+ CONTRACT_PATH = Path(__file__).resolve().parent.parent / "contracts" / "INSTANCE_CONTRACT_0.1.0.pdl"
25
+
26
+ # The schema dialects THIS Kernel build knows how to interpret — the way
27
+ # a browser understands a set of HTML versions, not "the one current
28
+ # version, everything else is outdated". Growing this set over time (as
29
+ # PACE adds Contract versions) means the Kernel learns to read more
30
+ # dialects; it does not mean older ones stop being valid. Whether a
31
+ # mismatch means "this instance needs pace migrate" or "this Kernel
32
+ # needs updating" depends on which side is actually behind — the Kernel
33
+ # cannot assume it's always the instance's fault.
34
+ SUPPORTED_SCHEMA_VERSIONS = {"0.1.0"}
35
+
36
+ # HARD_RULE 2 ("no code, script or executable file") is prose, not a
37
+ # machine-enumerable list — this is the Kernel's own codified reading of
38
+ # that rule, not something extracted from the contract text.
39
+ FORBIDDEN_SUFFIXES = {".py", ".ts", ".js", ".sh", ".exe", ".ps1", ".bat"}
40
+
41
+
42
+ def locate_instance(start: Path = None):
43
+ """Find the nearest .pace/ directory walking upward from `start`."""
44
+ return find_upward(".pace", start)
45
+
46
+
47
+ def validate_instance(root: Path) -> list:
48
+ """Structural validation only. Returns a list of violations; an
49
+ empty list means the instance is structurally valid."""
50
+ violations = []
51
+ contract = load_instance_contract(CONTRACT_PATH)
52
+
53
+ instance_file = root / "INSTANCE.pdl"
54
+ if not instance_file.is_file():
55
+ violations.append("missing INSTANCE.pdl")
56
+ else:
57
+ instance = read_pdl(instance_file)
58
+ # ORG_REF is excluded here: the contract marks it conditionally
59
+ # required (only when KIND=PROJECT), not unconditionally like
60
+ # the other fields — enforced explicitly just below instead.
61
+ required = [
62
+ field for field in contract["root_manifest"].get(".pace/INSTANCE.pdl", [])
63
+ if field != "ORG_REF"
64
+ ]
65
+ violations += require_fields(instance, required, "INSTANCE.pdl")
66
+ if instance.get("KIND") == "PROJECT" and not instance.get("ORG_REF"):
67
+ violations.append("INSTANCE.pdl KIND=PROJECT requires ORG_REF")
68
+ schema_version = instance.get("SCHEMA_VERSION")
69
+ if schema_version and schema_version not in SUPPORTED_SCHEMA_VERSIONS:
70
+ violations.append(
71
+ f"SCHEMA_VERSION {schema_version} is not understood by "
72
+ f"this PACE engine (understands: {sorted(SUPPORTED_SCHEMA_VERSIONS)}) "
73
+ "— either this instance needs pace migrate, or this "
74
+ "Kernel needs updating; pace migrate is not yet built"
75
+ )
76
+
77
+ active_versions_file = root / "ACTIVE_VERSIONS.pdl"
78
+ if not active_versions_file.is_file():
79
+ violations.append("missing ACTIVE_VERSIONS.pdl")
80
+ else:
81
+ active_versions = read_pdl(active_versions_file)
82
+ required = contract["root_manifest"].get(".pace/ACTIVE_VERSIONS.pdl", [])
83
+ violations += require_fields(active_versions, required, "ACTIVE_VERSIONS.pdl")
84
+
85
+ violations += require_dirs(root, sorted(contract["sections"]))
86
+ violations += require_non_empty_dir(root, "history")
87
+ violations += forbid_file_suffixes(root, FORBIDDEN_SUFFIXES)
88
+
89
+ return violations
90
+
91
+
92
+ if __name__ == "__main__":
93
+ target = Path(sys.argv[1]) if len(sys.argv) > 1 else None
94
+ root = locate_instance(target)
95
+ if root is None:
96
+ print("no .pace/ instance found")
97
+ raise SystemExit(1)
98
+ print(f"instance located at {root}")
99
+ violations = validate_instance(root)
100
+ if violations:
101
+ print(f"INVALID - {len(violations)} violation(s):")
102
+ for v in violations:
103
+ print(f" - {v}")
104
+ raise SystemExit(1)
105
+ print("VALID")
File without changes
@@ -0,0 +1,56 @@
1
+ """Loads contracts/INSTANCE_CONTRACT_*.pdl at runtime, instead of the
2
+ Kernel hardcoding a hand transcription of its rules.
3
+
4
+ Purpose-built for the Instance Contract's known document shape, not a
5
+ fully general PDL engine — see protocols/PDL_SPECIFICATION_0.2.0.pdl.
6
+ """
7
+
8
+ from pathlib import Path
9
+
10
+ from pace.services.pdl_nested import split_top_level_sections, indented_field_names
11
+
12
+ TOP_LEVEL_SECTIONS = [
13
+ "DEPENDS_ON", "PURPOSE", "ROOT_MANIFEST", "SECTIONS",
14
+ "NOT_REPRESENTED_HERE", "HARD_RULES",
15
+ ]
16
+
17
+ ROOT_MANIFEST_FILES = [".pace/INSTANCE.pdl", ".pace/ACTIVE_VERSIONS.pdl"]
18
+
19
+
20
+ def parse_root_manifest(root_manifest_text: str) -> dict:
21
+ files = split_top_level_sections(root_manifest_text, ROOT_MANIFEST_FILES)
22
+ return {
23
+ name: indented_field_names(body, "REQUIRED_FIELDS", base_indent=4)
24
+ for name, body in files.items()
25
+ }
26
+
27
+
28
+ def parse_sections(sections_text: str) -> dict:
29
+ """A SECTIONS entry header is a line at indentation 0, one or more
30
+ comma-separated paths (e.g. 'mission/, vision/, roadmap/, sprint/'
31
+ or a single 'history/'). Every section in Contract 0.1.0 requires
32
+ its folder to exist, so this only needs to collect the paths."""
33
+ sections = {}
34
+ for line in sections_text.splitlines():
35
+ if not line.strip():
36
+ continue
37
+ indent = len(line) - len(line.lstrip(" "))
38
+ if indent == 0:
39
+ for raw_path in line.strip().split(","):
40
+ path = raw_path.strip().rstrip("/")
41
+ if path:
42
+ sections[path] = {"required": True}
43
+ return sections
44
+
45
+
46
+ def load_instance_contract(path: Path) -> dict:
47
+ text = Path(path).read_text(encoding="utf-8")
48
+ first_line = text.splitlines()[0]
49
+ contract_version = first_line.split(" ", 1)[1].strip() if " " in first_line else ""
50
+
51
+ top = split_top_level_sections(text, TOP_LEVEL_SECTIONS)
52
+ return {
53
+ "contract_version": contract_version,
54
+ "root_manifest": parse_root_manifest(top.get("ROOT_MANIFEST", "")),
55
+ "sections": parse_sections(top.get("SECTIONS", "")),
56
+ }
@@ -0,0 +1,15 @@
1
+ """Generic filesystem helpers shared by the Kernel and, later, Engines."""
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def find_upward(name: str, start: Path = None):
7
+ """Walk upward from `start` (default: cwd) looking for a directory
8
+ called `name` — the way Git locates `.git/` from anywhere inside a
9
+ repository. Returns the matching Path, or None if not found."""
10
+ current = Path(start or Path.cwd()).resolve()
11
+ for directory in [current, *current.parents]:
12
+ candidate = directory / name
13
+ if candidate.is_dir():
14
+ return candidate
15
+ return None
@@ -0,0 +1,27 @@
1
+ """Minimal PDL parser for flat key-value documents.
2
+
3
+ Implements the grammar in protocols/PDL_SPECIFICATION_0.1.0.pdl: one
4
+ KEY VALUE pair per line, blank lines ignored, terminated by END.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+
10
+ def parse_pdl(text: str) -> dict:
11
+ fields = {}
12
+ for raw_line in text.splitlines():
13
+ line = raw_line.strip()
14
+ if not line:
15
+ continue
16
+ if line == "END":
17
+ break
18
+ if " " in line:
19
+ key, value = line.split(" ", 1)
20
+ else:
21
+ key, value = line, ""
22
+ fields[key] = value.strip()
23
+ return fields
24
+
25
+
26
+ def read_pdl(path: Path) -> dict:
27
+ return parse_pdl(Path(path).read_text(encoding="utf-8"))
@@ -0,0 +1,64 @@
1
+ """Nested-section extraction for PDL documents that mix structural
2
+ fields with hand-wrapped prose (governance/ontology/contracts documents),
3
+ on top of pdl.py's flat grammar.
4
+
5
+ See protocols/PDL_SPECIFICATION_0.2.0.pdl for why this deliberately does
6
+ not auto-detect section headers: a document that uses indentation both
7
+ for structure and for visual line-wrap alignment cannot be told apart
8
+ generically without guessing. Instead, the caller supplies the small,
9
+ fixed vocabulary of top-level section names it expects — the same
10
+ technique the old system's BOOTSTRAP_CONTEXT.pdl already used via its
11
+ own READ_ORDER list.
12
+ """
13
+
14
+
15
+ def split_top_level_sections(text: str, known_sections) -> dict:
16
+ """Split a document into named top-level blocks. A line is treated
17
+ as the start of a new section only if, once stripped, it exactly
18
+ matches one of `known_sections`. Everything up to the next known
19
+ section name (or END) becomes that section's raw body text."""
20
+ known = set(known_sections)
21
+ sections = {}
22
+ current_name = None
23
+ current_lines = []
24
+
25
+ def flush():
26
+ if current_name is not None:
27
+ sections[current_name] = "\n".join(current_lines).strip("\n")
28
+
29
+ for line in text.splitlines():
30
+ stripped = line.strip()
31
+ if stripped in known:
32
+ flush()
33
+ current_name = stripped
34
+ current_lines = []
35
+ elif stripped == "END":
36
+ break
37
+ elif current_name is not None:
38
+ current_lines.append(line)
39
+ flush()
40
+ return sections
41
+
42
+
43
+ def indented_field_names(text: str, header: str, base_indent: int) -> list:
44
+ """Within `text`, find the block introduced by a line equal to
45
+ `header`, then collect the first token of every subsequent line
46
+ indented at exactly `base_indent`. Lines indented deeper than
47
+ `base_indent` are continuations of the previous field's wrapped
48
+ value, not new fields, and are ignored here."""
49
+ names = []
50
+ in_block = False
51
+ for line in text.splitlines():
52
+ stripped = line.strip()
53
+ if not stripped:
54
+ continue
55
+ indent = len(line) - len(line.lstrip(" "))
56
+ if not in_block:
57
+ if stripped == header:
58
+ in_block = True
59
+ continue
60
+ if indent < base_indent:
61
+ break
62
+ if indent == base_indent:
63
+ names.append(stripped.split()[0])
64
+ return names
@@ -0,0 +1,36 @@
1
+ """Small, reusable validation helpers — generic enough for the Kernel
2
+ today and for a future Doctor/Validator engine, so validation logic
3
+ doesn't live inline inside any one caller."""
4
+
5
+ from pathlib import Path
6
+
7
+
8
+ def require_fields(data: dict, fields, context: str) -> list:
9
+ violations = []
10
+ for field in fields:
11
+ if not data.get(field):
12
+ violations.append(f"{context} missing required field {field}")
13
+ return violations
14
+
15
+
16
+ def require_dirs(root: Path, paths, label: str = "missing required section") -> list:
17
+ violations = []
18
+ for path in paths:
19
+ if not (root / path).is_dir():
20
+ violations.append(f"{label} {path}/")
21
+ return violations
22
+
23
+
24
+ def require_non_empty_dir(root: Path, path: str) -> list:
25
+ directory = root / path
26
+ if directory.is_dir() and not any(directory.iterdir()):
27
+ return [f"{path}/ exists but has no founding entry"]
28
+ return []
29
+
30
+
31
+ def forbid_file_suffixes(root: Path, suffixes) -> list:
32
+ violations = []
33
+ for path in root.rglob("*"):
34
+ if path.is_file() and path.suffix in suffixes:
35
+ violations.append(f"forbidden code/script file inside .pace/: {path.relative_to(root)}")
36
+ return violations
@@ -0,0 +1,7 @@
1
+ """PACE's own engine version — the single source of truth referenced by
2
+ Engines (when writing a new instance) and the Kernel (when reasoning
3
+ about instance compatibility). Independent of SCHEMA_VERSION: the engine
4
+ can evolve without the Instance Contract changing, and vice versa.
5
+ """
6
+
7
+ PACE_VERSION = "0.1.0"
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: pace-engine
3
+ Version: 0.1.0
4
+ Summary: PACE - an engineering operating system: a versioned, installable engine that preserves and governs a project's knowledge so any AI understands it in seconds.
5
+ Author: Cley Duarte
6
+ Project-URL: Homepage, https://github.com/cleyduartees-dot/PACE
7
+ Keywords: ai,knowledge,engineering,governance,memory,context
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+
11
+ # PACE
12
+
13
+ An engineering operating system: a versioned, installable engine that preserves, organizes, governs and evolves the architectural knowledge of software projects, in collaboration between people and AI.
14
+
15
+ PACE is not a library embedded inside a product. It is installed once and governs any number of independent projects, each carrying only its own `.pace/` memory — never a copy of PACE itself.
16
+
17
+ ## Status
18
+
19
+ Founded 2026-07-06. This repository currently contains only this founding commit. The minimal day-1 skeleton (kernel, services, engines, ontology, protocols, governance, policies, standards, contracts, cli, history, docs) is the next step, not yet built.
20
+
21
+ ## Founding principle
22
+
23
+ - **PACE** — the engine. Code only, versioned, installable. No knowledge of any specific organization or project.
24
+ - **Organización** — an adopting company's own governance memory (who holds authority, its own policies, its registry of projects), same recursive shape as a project instance, scoped one level up.
25
+ - **Instancia (`.pace/`)** — a single project's own memory: mission, vision, roadmap, sprint, handoff, history, decisions.
26
+ - **Proyecto** — the actual product codebase. Outside PACE's concern beyond hosting a `.pace/` folder at its root.
27
+
28
+ ## Roadmap (founding sequence)
29
+
30
+ 1. Crear el repositorio oficial PACE. — done
31
+ 2. Implementar el esqueleto mínimo.
32
+ 3. Implementar `pace init`.
33
+ 4. Adoptar el primer proyecto gobernado por PACE.
34
+ 5. Implementar `pace create`.
35
+ 6. Crear el primer proyecto nuevo nacido desde PACE.
@@ -0,0 +1,25 @@
1
+ README.md
2
+ pyproject.toml
3
+ pace/__init__.py
4
+ pace/cli/__init__.py
5
+ pace/cli/pace.py
6
+ pace/contracts/INSTANCE_CONTRACT_0.1.0.pdl
7
+ pace/contracts/__init__.py
8
+ pace/engines/__init__.py
9
+ pace/engines/handoff.py
10
+ pace/engines/memory.py
11
+ pace/engines/project_creator.py
12
+ pace/kernel/__init__.py
13
+ pace/kernel/kernel.py
14
+ pace/services/__init__.py
15
+ pace/services/contract_loader.py
16
+ pace/services/fs.py
17
+ pace/services/pdl.py
18
+ pace/services/pdl_nested.py
19
+ pace/services/validate.py
20
+ pace/services/version.py
21
+ pace_engine.egg-info/PKG-INFO
22
+ pace_engine.egg-info/SOURCES.txt
23
+ pace_engine.egg-info/dependency_links.txt
24
+ pace_engine.egg-info/entry_points.txt
25
+ pace_engine.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pace = pace.cli.pace:main
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pace-engine"
7
+ version = "0.1.0"
8
+ description = "PACE - an engineering operating system: a versioned, installable engine that preserves and governs a project's knowledge so any AI understands it in seconds."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ authors = [{ name = "Cley Duarte" }]
12
+ keywords = ["ai", "knowledge", "engineering", "governance", "memory", "context"]
13
+
14
+ [project.urls]
15
+ Homepage = "https://github.com/cleyduartees-dot/PACE"
16
+
17
+ [project.scripts]
18
+ pace = "pace.cli.pace:main"
19
+
20
+ [tool.setuptools]
21
+ packages = ["pace", "pace.cli", "pace.kernel", "pace.services", "pace.engines", "pace.contracts"]
22
+
23
+ [tool.setuptools.package-data]
24
+ "pace.contracts" = ["*.pdl"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+