framesdkpy 0.3.0__py3-none-any.whl

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,127 @@
1
+ """FrameExpect model and sub-models -- what must pass.
2
+
3
+ Mirrors schemas/json/expect.schema.json exactly.
4
+ The expect block feeds directly into the mechanical validator.
5
+ checks connect to rules.commands via command_ref.
6
+ pass_condition defines machine-parseable success criteria.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass, field
12
+
13
+ from framesdkpy.models.base import FrameBaseModel
14
+
15
+
16
+ # ---------------------------------------------------------------------------
17
+ # Sub-models
18
+ # ---------------------------------------------------------------------------
19
+
20
+
21
+ @dataclass(slots=True)
22
+ class MustHold(FrameBaseModel):
23
+ """Invariant that must remain true. Has an id for cross-referencing."""
24
+
25
+ id: str
26
+ """Stable identifier. maxLength: 100."""
27
+
28
+ statement: str
29
+ """The invariant statement. maxLength: 300."""
30
+
31
+ links: list[dict] = field(default_factory=list)
32
+ """Typed links from this entry to other FRAME refs."""
33
+
34
+
35
+ @dataclass(slots=True)
36
+ class Check(FrameBaseModel):
37
+ """Verification check that feeds the mechanical validator.
38
+
39
+ command_ref points to rules.commands.<name> -- the shell command to execute.
40
+ pass_condition is machine-parseable: 'exit_code == 0', 'stdout contains X',
41
+ 'stdout matches REGEX', or 'file_exists PATH'.
42
+ """
43
+
44
+ name: str
45
+ """Short check name displayed in reports. maxLength: 100."""
46
+
47
+ what: str
48
+ """What is being checked -- human-readable explanation. maxLength: 300."""
49
+
50
+ how: str | None = None
51
+ """How the check works: test, build, lint, grep, manual. maxLength: 200."""
52
+
53
+ command_ref: str | None = None
54
+ """Ref to rules.commands.<name> for executable verification. maxLength: 200."""
55
+
56
+ pass_condition: str | None = None
57
+ """Machine-parseable success criteria. Examples:
58
+ 'exit_code == 0'
59
+ 'stdout contains BUILD SUCCESS'
60
+ 'stdout matches ^[a-f0-9]{12}_'
61
+ 'file_exists dist/index.html'
62
+ """
63
+
64
+ links: list[dict] = field(default_factory=list)
65
+ """Typed links from this entry to other FRAME refs."""
66
+
67
+
68
+ @dataclass(slots=True)
69
+ class Proof(FrameBaseModel):
70
+ """Required evidence type. Has an id for cross-referencing.
71
+
72
+ type: review (human review needed), smoke_test (quick sanity check),
73
+ static_check (linter/type checker), unavailable (can't verify yet).
74
+ """
75
+
76
+ id: str
77
+ """Stable identifier. maxLength: 100."""
78
+
79
+ type: str
80
+ """Fixed enum: review, smoke_test, static_check, unavailable."""
81
+
82
+ description: str
83
+ """What evidence is needed. maxLength: 300."""
84
+
85
+ links: list[dict] = field(default_factory=list)
86
+ """Typed links from this entry to other FRAME refs."""
87
+
88
+
89
+ # ---------------------------------------------------------------------------
90
+ # Main model
91
+ # ---------------------------------------------------------------------------
92
+
93
+
94
+ @dataclass(slots=True)
95
+ class FrameExpect(FrameBaseModel):
96
+ """What must pass -- outcomes, invariants, checks, proof requirements.
97
+
98
+ Populated from expect.yaml. This is the contract the mechanical validator
99
+ enforces. checks connect to rules.commands via command_ref.
100
+ """
101
+
102
+ frame: dict = field(default_factory=dict)
103
+ """Shared FRAME header block. Required by every FRAME file."""
104
+
105
+ outcomes: dict | None = None
106
+ """Named expected results of work. Keys are outcome names."""
107
+
108
+ must_hold: list[MustHold] = field(default_factory=list)
109
+ """Invariants that must stay true. Each has a stable id."""
110
+
111
+ checks: dict[str, Check] = field(default_factory=dict)
112
+ """Verification checks. Key is the check name -- used as command_ref target."""
113
+
114
+ done_when: dict | None = None
115
+ """Completion conditions. Free-form keys."""
116
+
117
+ proof: list[Proof] = field(default_factory=list)
118
+ """Required evidence types. Each has a stable id."""
119
+
120
+ handoff: dict | None = None
121
+ """State to pass to the next session. Free-form."""
122
+
123
+ evidence: list[dict] = field(default_factory=list)
124
+ """Evidence entries supporting Expect claims."""
125
+
126
+ links: list[dict] = field(default_factory=list)
127
+ """Typed links from this file to other FRAME refs."""
@@ -0,0 +1,163 @@
1
+ """FrameFacts model and sub-models -- stable project truth.
2
+
3
+ Mirrors schemas/json/facts.schema.json exactly. Required fields are
4
+ non-nullable (str, not str | None). The loader guarantees these are
5
+ populated before model construction. Optional fields use | None.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+
12
+ from framesdkpy.models.base import FrameBaseModel
13
+
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Sub-models -- typed representations of Facts blocks
17
+ # ---------------------------------------------------------------------------
18
+
19
+
20
+ @dataclass(slots=True)
21
+ class Profile(FrameBaseModel):
22
+ """Project identity. name and summary are always present."""
23
+
24
+ name: str
25
+ """Project name. maxLength: 100."""
26
+
27
+ summary: str
28
+ """One-paragraph project description. maxLength: 300."""
29
+
30
+ repo_shape: str | None = None
31
+ """Enum: split-backend-frontend, monorepo, single-package, monolith, microservices."""
32
+
33
+ delivery_family: str | None = None
34
+ """Enum: cli, web-app, mobile-app, sdk, infra-tooling, data-pipeline, etc."""
35
+
36
+
37
+ @dataclass(slots=True)
38
+ class Architecture(FrameBaseModel):
39
+ """System layout. summary is always present."""
40
+
41
+ summary: str
42
+ """Human-readable system layout overview. maxLength: 500."""
43
+
44
+ backend_layers: list[str] | None = None
45
+ """Ordered list of backend architectural layers, e.g. ['routes', 'services', 'models']."""
46
+
47
+ frontend_layers: list[str] | None = None
48
+ """Ordered list of frontend layers, e.g. ['views', 'stores', 'services']."""
49
+
50
+ data_flow: str | None = None
51
+ """Description of how data moves through the system. maxLength: 500."""
52
+
53
+ deployment_topology: str | None = None
54
+ """Where and how the system is deployed. maxLength: 500."""
55
+
56
+
57
+ @dataclass(slots=True)
58
+ class Technology(FrameBaseModel):
59
+ """Structured technology stack. Required fields are present when this block exists."""
60
+
61
+ language: str
62
+ """Primary programming language. maxLength: 100."""
63
+
64
+ framework: str
65
+ """Primary framework (FastAPI, Next.js, etc.). maxLength: 100."""
66
+
67
+ database: str
68
+ """Primary database (PostgreSQL, SQLite, etc.). maxLength: 100."""
69
+
70
+ extensions: dict | None = None
71
+ """Optional free-form extensions for additional tech details."""
72
+
73
+
74
+ @dataclass(slots=True)
75
+ class Source(FrameBaseModel):
76
+ """Trusted source-of-truth file. Has an id for cross-referencing."""
77
+
78
+ id: str
79
+ """Stable identifier -- other files reference this via 'facts.sources.<id>'. maxLength: 100."""
80
+
81
+ path: str
82
+ """Filesystem path to the source file. maxLength: 200."""
83
+
84
+ purpose: str
85
+ """Why this file is a source of truth. maxLength: 300."""
86
+
87
+
88
+ @dataclass(slots=True)
89
+ class Quirk(FrameBaseModel):
90
+ """Weird project-specific thing agents must understand. Has an id for cross-referencing."""
91
+
92
+ id: str
93
+ """Stable identifier. maxLength: 100."""
94
+
95
+ description: str
96
+ """What the quirk is. maxLength: 200."""
97
+
98
+ why: str
99
+ """Why this quirk exists -- prevents agents from 'fixing' it. maxLength: 300."""
100
+
101
+
102
+ @dataclass(slots=True)
103
+ class OpenQuestion(FrameBaseModel):
104
+ """Thing nobody has decided yet. Has an id for cross-referencing."""
105
+
106
+ id: str
107
+ """Stable identifier. maxLength: 100."""
108
+
109
+ question: str
110
+ """The unresolved question. maxLength: 300."""
111
+
112
+ context: str
113
+ """Background needed to understand the question. maxLength: 300."""
114
+
115
+
116
+ # ---------------------------------------------------------------------------
117
+ # Main model
118
+ # ---------------------------------------------------------------------------
119
+
120
+
121
+ @dataclass(slots=True)
122
+ class FrameFacts(FrameBaseModel):
123
+ """Stable project truth -- what the project is, how it's built, its quirks.
124
+
125
+ Populated by the loader from facts.yaml. Required fields are non-nullable.
126
+ Optional blocks (environments, persistence, classification) use | None.
127
+ """
128
+
129
+ frame: dict
130
+ """Shared FRAME header block. Required by every FRAME file."""
131
+
132
+ profile: Profile
133
+ """Required. Every project has a name and summary."""
134
+
135
+ architecture: Architecture
136
+ """Required. Every project has a system layout."""
137
+
138
+ sources: list[Source] = field(default_factory=list)
139
+ """Trusted source-of-truth files. Each has a stable id for cross-referencing."""
140
+
141
+ quirks: list[Quirk] = field(default_factory=list)
142
+ """Project-specific oddities agents must understand. Each has a stable id."""
143
+
144
+ open_questions: list[OpenQuestion] = field(default_factory=list)
145
+ """Unresolved questions. Each has a stable id."""
146
+
147
+ classification: dict | None = None
148
+ """Project classification details. Free-form -- varies per project."""
149
+
150
+ technology: Technology | None = None
151
+ """Structured technology stack. Optional at first."""
152
+
153
+ environments: dict | None = None
154
+ """Per-environment configuration. Free-form keys (local, production, staging)."""
155
+
156
+ persistence: dict | None = None
157
+ """Database, ORM, migration, and storage details. Free-form -- varies by ORM/storage."""
158
+
159
+ evidence: list[dict] = field(default_factory=list)
160
+ """Evidence entries supporting Facts claims."""
161
+
162
+ links: list[dict] = field(default_factory=list)
163
+ """Typed links from this file to other FRAME refs."""
@@ -0,0 +1,42 @@
1
+ """FRAME -- the assembled whole.
2
+
3
+ Composes all five typed parts into one model. All 5 files must be present
4
+ in the .haxaml/ directory at all times (D3: strict single-directory discovery).
5
+ Empty files are valid -- content depth is Haxaml's concern, not the SDK's.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+ from framesdkpy.models.base import FrameBaseModel
13
+ from framesdkpy.models.facts_model import FrameFacts
14
+ from framesdkpy.models.rules_model import FrameRules
15
+ from framesdkpy.models.map_model import FrameMap
16
+ from framesdkpy.models.expect_model import FrameExpect
17
+ from framesdkpy.models.acts_model import FrameActs
18
+
19
+
20
+ @dataclass(slots=True)
21
+ class FRAME(FrameBaseModel):
22
+ """The assembled FRAME object -- all five parts in one typed model.
23
+
24
+ All 5 files are required by the loader (D3). Content depth varies --
25
+ a new project has empty Expect and Acts. A mature project fills them.
26
+ The SDK validates structure and schema. Haxaml enforces content.
27
+ """
28
+
29
+ facts: FrameFacts
30
+ """Required. Stable project truth -- identity, stack, architecture, quirks."""
31
+
32
+ rules: FrameRules
33
+ """Required. Governance constraints, commands, policies."""
34
+
35
+ map: FrameMap
36
+ """Required. Where things live -- at minimum structure + roots."""
37
+
38
+ expect: FrameExpect
39
+ """Required. What must pass -- may be empty in early projects."""
40
+
41
+ acts: FrameActs
42
+ """Required. Run history -- starts empty, grows over time."""
@@ -0,0 +1,157 @@
1
+ """FrameMap model and sub-models -- where things live in the repo.
2
+
3
+ Mirrors schemas/json/map.schema.json exactly.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+
10
+ from framesdkpy.models.base import FrameBaseModel
11
+
12
+
13
+ # ---------------------------------------------------------------------------
14
+ # Sub-models
15
+ # ---------------------------------------------------------------------------
16
+
17
+
18
+ @dataclass(slots=True)
19
+ class Group(FrameBaseModel):
20
+ """Logical grouping of paths. Supports wildcards for flexible coverage.
21
+
22
+ Groups let the map cover growing repos without requiring every new file
23
+ to be individually registered.
24
+ """
25
+
26
+ id: str
27
+ """Stable identifier for cross-referencing. maxLength: 100."""
28
+
29
+ label: str
30
+ """Human-readable group name. maxLength: 150."""
31
+
32
+ paths: list[str] = field(default_factory=list)
33
+ """File/directory paths in this group. Wildcards allowed (e.g. 'Backend/app/**/*.py')."""
34
+
35
+ links: list[dict] = field(default_factory=list)
36
+ """Typed links from this entry to other FRAME refs."""
37
+
38
+
39
+ @dataclass(slots=True)
40
+ class PathEntry(FrameBaseModel):
41
+ """Critical individual file. Explicit path only -- no wildcards.
42
+
43
+ Optional id for cross-referencing from expect.checks or acts.runs.touched.
44
+ """
45
+
46
+ path: str
47
+ """Filesystem path. maxLength: 200."""
48
+
49
+ purpose: str
50
+ """Why this file is important. maxLength: 300."""
51
+
52
+ id: str | None = None
53
+ """Optional stable identifier. Only needed when this path is referenced from another file."""
54
+
55
+ links: list[dict] = field(default_factory=list)
56
+ """Typed links from this entry to other FRAME refs."""
57
+
58
+
59
+ @dataclass(slots=True)
60
+ class Entrypoint(FrameBaseModel):
61
+ """CLI, API, web, or script entry point. Always has an id for cross-referencing."""
62
+
63
+ id: str
64
+ """Stable identifier. maxLength: 100."""
65
+
66
+ path: str
67
+ """Filesystem path to the entry point. maxLength: 200."""
68
+
69
+ kind: str
70
+ """Fixed enum: cli, api, web, script."""
71
+
72
+ description: str | None = None
73
+ """What this entry point does. maxLength: 300."""
74
+
75
+ links: list[dict] = field(default_factory=list)
76
+ """Typed links from this entry to other FRAME refs."""
77
+
78
+
79
+ @dataclass(slots=True)
80
+ class ManagedPath(FrameBaseModel):
81
+ """Path under special rule. Supports wildcards.
82
+
83
+ rule: generated (auto-generated files), config (.env, settings files),
84
+ immutable (migration files, lock files).
85
+ """
86
+
87
+ path: str
88
+ """Filesystem path or wildcard pattern. maxLength: 200."""
89
+
90
+ rule: str
91
+ """Fixed enum: generated, config, immutable."""
92
+
93
+ id: str | None = None
94
+ """Optional stable identifier for cross-referencing from rules.donts or expect.checks."""
95
+
96
+ links: list[dict] = field(default_factory=list)
97
+ """Typed links from this entry to other FRAME refs."""
98
+
99
+
100
+ @dataclass(slots=True)
101
+ class UnmappedPath(FrameBaseModel):
102
+ """Path not yet placed in the map. Honest about gaps -- invites improvement."""
103
+
104
+ path: str
105
+ """Filesystem path that needs mapping. maxLength: 200."""
106
+
107
+ reason: str
108
+ """Why this path hasn't been mapped yet. maxLength: 200."""
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Main model
113
+ # ---------------------------------------------------------------------------
114
+
115
+
116
+ @dataclass(slots=True)
117
+ class FrameMap(FrameBaseModel):
118
+ """Where things live in the repo. Populated from map.yaml.
119
+
120
+ structure provides a quick visual overview (top block).
121
+ roots describe top-level directories.
122
+ groups provide logical groupings with wildcard support.
123
+ paths list critical individual files.
124
+ entrypoints show CLI/API/web start points.
125
+ managed_paths declare files under special rules.
126
+ unmapped_paths acknowledge gaps.
127
+ """
128
+
129
+ frame: dict = field(default_factory=dict)
130
+ """Shared FRAME header block. Required by every FRAME file."""
131
+
132
+ structure: str | None = None
133
+ """Quick visual overview of repo layout. Top block, maxLength: 800."""
134
+
135
+ roots: dict | None = None
136
+ """Top-level directory purposes. Free-form keys."""
137
+
138
+ groups: list[Group] = field(default_factory=list)
139
+ """Logical groupings of paths. Supports wildcards."""
140
+
141
+ paths: list[PathEntry] = field(default_factory=list)
142
+ """Critical individual files. Explicit paths only."""
143
+
144
+ entrypoints: list[Entrypoint] = field(default_factory=list)
145
+ """CLI/API/web entry points. Each has a stable id."""
146
+
147
+ managed_paths: list[ManagedPath] = field(default_factory=list)
148
+ """Paths under special rules. Supports wildcards."""
149
+
150
+ unmapped_paths: list[UnmappedPath] = field(default_factory=list)
151
+ """Paths not yet mapped. Honest about gaps."""
152
+
153
+ evidence: list[dict] = field(default_factory=list)
154
+ """Evidence entries supporting Map claims."""
155
+
156
+ links: list[dict] = field(default_factory=list)
157
+ """Typed links from this file to other FRAME refs."""
@@ -0,0 +1,181 @@
1
+ """FrameRules model and sub-models -- how to work safely in this repo.
2
+
3
+ Mirrors schemas/json/rules.schema.json exactly.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+
10
+ from framesdkpy.models.base import FrameBaseModel
11
+
12
+
13
+ # ---------------------------------------------------------------------------
14
+ # Sub-models
15
+ # ---------------------------------------------------------------------------
16
+
17
+
18
+ @dataclass(slots=True)
19
+ class Policy(FrameBaseModel):
20
+ """Durable project policy (role access, lifecycle, audit, auth).
21
+
22
+ Moved from Facts to Rules -- policies are behavioral constraints,
23
+ not current project truth.
24
+ """
25
+
26
+ id: str
27
+ """Stable identifier for cross-referencing. maxLength: 100."""
28
+
29
+ name: str
30
+ """Short policy name. maxLength: 150."""
31
+
32
+ rule: str
33
+ """The policy rule text. maxLength: 500."""
34
+
35
+ links: list[dict] = field(default_factory=list)
36
+ """Typed links from this entry to other FRAME refs."""
37
+
38
+
39
+ @dataclass(slots=True)
40
+ class CoreRule(FrameBaseModel):
41
+ """Core behavioral constraint. Has an id for cross-referencing."""
42
+
43
+ id: str
44
+ """Stable identifier. maxLength: 100."""
45
+
46
+ rule: str
47
+ """The constraint text. maxLength: 500."""
48
+
49
+ links: list[dict] = field(default_factory=list)
50
+ """Typed links from this entry to other FRAME refs."""
51
+
52
+
53
+ @dataclass(slots=True)
54
+ class Command(FrameBaseModel):
55
+ """Named shell command with a fixed schema.
56
+
57
+ kind: setup (install deps), verify (validation check), or run (server/interactive).
58
+ The mechanical validator uses kind to decide which commands to execute.
59
+ """
60
+
61
+ run: str
62
+ """Shell command to execute. maxLength: 500."""
63
+
64
+ kind: str
65
+ """Fixed enum: setup, verify, run."""
66
+
67
+ purpose: str
68
+ """Why this command exists. maxLength: 300."""
69
+
70
+ links: list[dict] = field(default_factory=list)
71
+ """Typed links from this entry to other FRAME refs."""
72
+
73
+
74
+ @dataclass(slots=True)
75
+ class Dont(FrameBaseModel):
76
+ """Thing you must never do. severity: critical (blocks) or warning (flags)."""
77
+
78
+ id: str
79
+ """Stable identifier. maxLength: 100."""
80
+
81
+ rule: str
82
+ """The forbidden action. maxLength: 300."""
83
+
84
+ severity: str = "critical"
85
+ """Enum: critical, warning. critical blocks the agent; warning flags it."""
86
+
87
+ links: list[dict] = field(default_factory=list)
88
+ """Typed links from this entry to other FRAME refs."""
89
+
90
+
91
+ @dataclass(slots=True)
92
+ class AskFirst(FrameBaseModel):
93
+ """Trigger needing human approval before the agent proceeds.
94
+
95
+ trigger_type: file_pattern (matches against files the agent will touch)
96
+ or task_pattern (matches against the agent's stated task description).
97
+ """
98
+
99
+ id: str
100
+ """Stable identifier. maxLength: 100."""
101
+
102
+ trigger_type: str
103
+ """Fixed enum: file_pattern, task_pattern."""
104
+
105
+ trigger: str
106
+ """The pattern to match against. maxLength: 300."""
107
+
108
+ reason: str
109
+ """Why approval is needed. maxLength: 300."""
110
+
111
+ links: list[dict] = field(default_factory=list)
112
+ """Typed links from this entry to other FRAME refs."""
113
+
114
+
115
+ @dataclass(slots=True)
116
+ class Hint(FrameBaseModel):
117
+ """Skill reference, known gotcha, or task-specific guidance.
118
+
119
+ Hints are not enforced -- they help the agent work faster.
120
+ """
121
+
122
+ id: str
123
+ """Stable identifier. maxLength: 100."""
124
+
125
+ hint: str
126
+ """The guidance text. maxLength: 300."""
127
+
128
+ links: list[dict] = field(default_factory=list)
129
+ """Typed links from this entry to other FRAME refs."""
130
+
131
+
132
+ # ---------------------------------------------------------------------------
133
+ # Main model
134
+ # ---------------------------------------------------------------------------
135
+
136
+
137
+ @dataclass(slots=True)
138
+ class FrameRules(FrameBaseModel):
139
+ """How to work safely in this repo. Populated from rules.yaml.
140
+
141
+ governance_level controls enforcement strictness:
142
+ relaxed → agents proceed freely, ask_first is advisory
143
+ normal → ask_first warns but doesn't block
144
+ strict → ask_first blocks, donts enforced, validator must pass
145
+ """
146
+
147
+ frame: dict = field(default_factory=dict)
148
+ """Shared FRAME header block. Required by every FRAME file."""
149
+
150
+ governance_level: str = "normal"
151
+ """Enum: relaxed, normal, strict. Controls Haxaml enforcement strictness."""
152
+
153
+ rules: list[CoreRule] = field(default_factory=list)
154
+ """Core behavioral constraints."""
155
+
156
+ policies: list[Policy] = field(default_factory=list)
157
+ """Durable project policies (role access, lifecycle, audit)."""
158
+
159
+ commands: dict[str, Command] = field(default_factory=dict)
160
+ """Named shell commands. Key is the command name used by expect.checks.command_ref."""
161
+
162
+ donts: list[Dont] = field(default_factory=list)
163
+ """Things you must never do. severity determines enforcement."""
164
+
165
+ ask_first: list[AskFirst] = field(default_factory=list)
166
+ """Triggers needing human approval. Enforcement depends on governance_level."""
167
+
168
+ hints: list[Hint] = field(default_factory=list)
169
+ """Skill references, gotchas, task-specific guidance."""
170
+
171
+ code_style: dict | None = None
172
+ """Formatting, naming, conventions. Free-form -- varies per language. Advisory limit 1000 chars."""
173
+
174
+ git: dict | None = None
175
+ """Branch strategy, commit style, PR rules. Free-form -- varies per team. Advisory limit 1000 chars."""
176
+
177
+ evidence: list[dict] = field(default_factory=list)
178
+ """Evidence entries supporting Rules claims."""
179
+
180
+ links: list[dict] = field(default_factory=list)
181
+ """Typed links from this file to other FRAME refs."""