faf-python-sdk 1.0.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.
- faf_python_sdk-1.0.0/.github/workflows/pypi.yml +14 -0
- faf_python_sdk-1.0.0/.gitignore +44 -0
- faf_python_sdk-1.0.0/LICENSE +21 -0
- faf_python_sdk-1.0.0/PKG-INFO +224 -0
- faf_python_sdk-1.0.0/README.md +192 -0
- faf_python_sdk-1.0.0/docs/GROK-INTEGRATION.md +322 -0
- faf_python_sdk-1.0.0/docs/TECHNICAL-SPEC.md +467 -0
- faf_python_sdk-1.0.0/examples/basic_usage.py +123 -0
- faf_python_sdk-1.0.0/examples/grok_integration.py +241 -0
- faf_python_sdk-1.0.0/faf_sdk/__init__.py +55 -0
- faf_python_sdk-1.0.0/faf_sdk/discovery.py +378 -0
- faf_python_sdk-1.0.0/faf_sdk/parser.py +194 -0
- faf_python_sdk-1.0.0/faf_sdk/types.py +211 -0
- faf_python_sdk-1.0.0/faf_sdk/validator.py +213 -0
- faf_python_sdk-1.0.0/pyproject.toml +66 -0
- faf_python_sdk-1.0.0/tests/__init__.py +1 -0
- faf_python_sdk-1.0.0/tests/stress_test.py +612 -0
- faf_python_sdk-1.0.0/tests/test_discovery.py +184 -0
- faf_python_sdk-1.0.0/tests/test_parser.py +145 -0
- faf_python_sdk-1.0.0/tests/test_validator.py +157 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on: workflow_dispatch
|
|
3
|
+
jobs:
|
|
4
|
+
publish:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
permissions:
|
|
7
|
+
id-token: write
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
- uses: actions/setup-python@v5
|
|
11
|
+
with:
|
|
12
|
+
python-version: "3.11"
|
|
13
|
+
- run: pip install build && python -m build
|
|
14
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
venv/
|
|
25
|
+
.venv/
|
|
26
|
+
env/
|
|
27
|
+
.env/
|
|
28
|
+
|
|
29
|
+
# Testing
|
|
30
|
+
.pytest_cache/
|
|
31
|
+
.coverage
|
|
32
|
+
htmlcov/
|
|
33
|
+
.tox/
|
|
34
|
+
.nox/
|
|
35
|
+
|
|
36
|
+
# IDE
|
|
37
|
+
.vscode/
|
|
38
|
+
.idea/
|
|
39
|
+
*.swp
|
|
40
|
+
*.swo
|
|
41
|
+
|
|
42
|
+
# OS
|
|
43
|
+
.DS_Store
|
|
44
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 wolfejam
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: faf-python-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for FAF (Foundational AI-context Format) - IANA-registered application/vnd.faf+yaml
|
|
5
|
+
Project-URL: Homepage, https://faf.one
|
|
6
|
+
Project-URL: Documentation, https://github.com/Wolfe-Jam/faf-python-sdk
|
|
7
|
+
Project-URL: Repository, https://github.com/Wolfe-Jam/faf-python-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/Wolfe-Jam/faf-python-sdk/issues
|
|
9
|
+
Author-email: wolfejam <wolfejam@faf.one>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai-context,claude,faf,grok,mcp,project-context,yaml
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Requires-Dist: pyyaml>=6.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# faf-sdk
|
|
34
|
+
|
|
35
|
+
Python SDK for **FAF (Foundational AI-context Format)** - the IANA-registered format for AI project context.
|
|
36
|
+
|
|
37
|
+
**Media Type:** `application/vnd.faf+yaml`
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install faf-sdk
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from faf_sdk import parse, validate, find_faf_file
|
|
49
|
+
|
|
50
|
+
# Find and parse project.faf
|
|
51
|
+
path = find_faf_file()
|
|
52
|
+
if path:
|
|
53
|
+
with open(path) as f:
|
|
54
|
+
faf = parse(f.read())
|
|
55
|
+
|
|
56
|
+
print(f"Project: {faf.project_name}")
|
|
57
|
+
print(f"Score: {faf.score}%")
|
|
58
|
+
print(f"Stack: {faf.data.instant_context.tech_stack}")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Core Functions
|
|
62
|
+
|
|
63
|
+
### Parsing
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from faf_sdk import parse, parse_file, stringify
|
|
67
|
+
|
|
68
|
+
# Parse from string
|
|
69
|
+
faf = parse(yaml_content)
|
|
70
|
+
|
|
71
|
+
# Parse from file
|
|
72
|
+
faf = parse_file("project.faf")
|
|
73
|
+
|
|
74
|
+
# Access typed data
|
|
75
|
+
print(faf.data.project.name)
|
|
76
|
+
print(faf.data.instant_context.what_building)
|
|
77
|
+
print(faf.data.stack.frontend)
|
|
78
|
+
|
|
79
|
+
# Access raw dict
|
|
80
|
+
print(faf.raw["project"]["goal"])
|
|
81
|
+
|
|
82
|
+
# Convert back to YAML
|
|
83
|
+
yaml_str = stringify(faf)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Validation
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from faf_sdk import validate
|
|
90
|
+
|
|
91
|
+
result = validate(faf)
|
|
92
|
+
|
|
93
|
+
if result.valid:
|
|
94
|
+
print(f"Valid! Score: {result.score}%")
|
|
95
|
+
else:
|
|
96
|
+
print("Errors:", result.errors)
|
|
97
|
+
|
|
98
|
+
print("Warnings:", result.warnings)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### File Discovery
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from faf_sdk import find_faf_file, find_project_root, load_fafignore
|
|
105
|
+
|
|
106
|
+
# Find project.faf (walks up directory tree)
|
|
107
|
+
path = find_faf_file("/path/to/src")
|
|
108
|
+
|
|
109
|
+
# Find project root
|
|
110
|
+
root = find_project_root()
|
|
111
|
+
|
|
112
|
+
# Load ignore patterns
|
|
113
|
+
patterns = load_fafignore(root)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## FAF File Structure
|
|
117
|
+
|
|
118
|
+
A `.faf` file provides instant project context for AI:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
faf_version: 2.5.0
|
|
122
|
+
ai_score: 85%
|
|
123
|
+
ai_confidence: HIGH
|
|
124
|
+
|
|
125
|
+
project:
|
|
126
|
+
name: my-project
|
|
127
|
+
goal: Build a CLI tool for data processing
|
|
128
|
+
|
|
129
|
+
instant_context:
|
|
130
|
+
what_building: CLI data processing tool
|
|
131
|
+
tech_stack: Python 3.11, Click, Pandas
|
|
132
|
+
key_files:
|
|
133
|
+
- src/cli.py
|
|
134
|
+
- src/processor.py
|
|
135
|
+
|
|
136
|
+
stack:
|
|
137
|
+
frontend: None
|
|
138
|
+
backend: Python
|
|
139
|
+
database: SQLite
|
|
140
|
+
infrastructure: Docker
|
|
141
|
+
|
|
142
|
+
human_context:
|
|
143
|
+
who: Data analysts
|
|
144
|
+
what: Process CSV files efficiently
|
|
145
|
+
why: Current tools are slow
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Type Definitions
|
|
149
|
+
|
|
150
|
+
The SDK provides typed access to all FAF sections:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from faf_sdk import (
|
|
154
|
+
FafData,
|
|
155
|
+
ProjectInfo,
|
|
156
|
+
StackInfo,
|
|
157
|
+
InstantContext,
|
|
158
|
+
ContextQuality,
|
|
159
|
+
HumanContext
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# All fields are optional except faf_version and project.name
|
|
163
|
+
faf = parse(content)
|
|
164
|
+
|
|
165
|
+
# Typed access
|
|
166
|
+
project: ProjectInfo = faf.data.project
|
|
167
|
+
stack: StackInfo = faf.data.stack
|
|
168
|
+
context: InstantContext = faf.data.instant_context
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Integration Example
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from faf_sdk import find_faf_file, parse_file, validate
|
|
175
|
+
|
|
176
|
+
def get_project_context():
|
|
177
|
+
"""Load project context for AI processing"""
|
|
178
|
+
path = find_faf_file()
|
|
179
|
+
if not path:
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
faf = parse_file(path)
|
|
183
|
+
result = validate(faf)
|
|
184
|
+
|
|
185
|
+
if not result.valid:
|
|
186
|
+
raise ValueError(f"Invalid FAF: {result.errors}")
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
"name": faf.data.project.name,
|
|
190
|
+
"goal": faf.data.project.goal,
|
|
191
|
+
"stack": faf.data.instant_context.tech_stack if faf.data.instant_context else None,
|
|
192
|
+
"key_files": faf.data.instant_context.key_files if faf.data.instant_context else [],
|
|
193
|
+
"score": faf.score,
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Use in AI context
|
|
197
|
+
context = get_project_context()
|
|
198
|
+
if context:
|
|
199
|
+
print(f"Working on: {context['name']}")
|
|
200
|
+
print(f"Goal: {context['goal']}")
|
|
201
|
+
print(f"Tech: {context['stack']}")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Why FAF?
|
|
205
|
+
|
|
206
|
+
Every AI conversation starts from zero. No memory of your project. No understanding of your stack. Just vibes.
|
|
207
|
+
|
|
208
|
+
FAF solves this with a single, IANA-registered file that gives AI instant project context:
|
|
209
|
+
|
|
210
|
+
- **One file, one read, full understanding**
|
|
211
|
+
- **19ms average execution**
|
|
212
|
+
- **Zero setup friction**
|
|
213
|
+
- **MIT licensed, works everywhere**
|
|
214
|
+
|
|
215
|
+
## Links
|
|
216
|
+
|
|
217
|
+
- **Spec:** [github.com/Wolfe-Jam/faf](https://github.com/Wolfe-Jam/faf)
|
|
218
|
+
- **Site:** [faf.one](https://faf.one)
|
|
219
|
+
- **MCP Server:** [claude-faf-mcp](https://github.com/modelcontextprotocol/servers/tree/main/src/faf)
|
|
220
|
+
- **IANA Registration:** `application/vnd.faf+yaml`
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# faf-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for **FAF (Foundational AI-context Format)** - the IANA-registered format for AI project context.
|
|
4
|
+
|
|
5
|
+
**Media Type:** `application/vnd.faf+yaml`
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install faf-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from faf_sdk import parse, validate, find_faf_file
|
|
17
|
+
|
|
18
|
+
# Find and parse project.faf
|
|
19
|
+
path = find_faf_file()
|
|
20
|
+
if path:
|
|
21
|
+
with open(path) as f:
|
|
22
|
+
faf = parse(f.read())
|
|
23
|
+
|
|
24
|
+
print(f"Project: {faf.project_name}")
|
|
25
|
+
print(f"Score: {faf.score}%")
|
|
26
|
+
print(f"Stack: {faf.data.instant_context.tech_stack}")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Core Functions
|
|
30
|
+
|
|
31
|
+
### Parsing
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from faf_sdk import parse, parse_file, stringify
|
|
35
|
+
|
|
36
|
+
# Parse from string
|
|
37
|
+
faf = parse(yaml_content)
|
|
38
|
+
|
|
39
|
+
# Parse from file
|
|
40
|
+
faf = parse_file("project.faf")
|
|
41
|
+
|
|
42
|
+
# Access typed data
|
|
43
|
+
print(faf.data.project.name)
|
|
44
|
+
print(faf.data.instant_context.what_building)
|
|
45
|
+
print(faf.data.stack.frontend)
|
|
46
|
+
|
|
47
|
+
# Access raw dict
|
|
48
|
+
print(faf.raw["project"]["goal"])
|
|
49
|
+
|
|
50
|
+
# Convert back to YAML
|
|
51
|
+
yaml_str = stringify(faf)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Validation
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from faf_sdk import validate
|
|
58
|
+
|
|
59
|
+
result = validate(faf)
|
|
60
|
+
|
|
61
|
+
if result.valid:
|
|
62
|
+
print(f"Valid! Score: {result.score}%")
|
|
63
|
+
else:
|
|
64
|
+
print("Errors:", result.errors)
|
|
65
|
+
|
|
66
|
+
print("Warnings:", result.warnings)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### File Discovery
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from faf_sdk import find_faf_file, find_project_root, load_fafignore
|
|
73
|
+
|
|
74
|
+
# Find project.faf (walks up directory tree)
|
|
75
|
+
path = find_faf_file("/path/to/src")
|
|
76
|
+
|
|
77
|
+
# Find project root
|
|
78
|
+
root = find_project_root()
|
|
79
|
+
|
|
80
|
+
# Load ignore patterns
|
|
81
|
+
patterns = load_fafignore(root)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## FAF File Structure
|
|
85
|
+
|
|
86
|
+
A `.faf` file provides instant project context for AI:
|
|
87
|
+
|
|
88
|
+
```yaml
|
|
89
|
+
faf_version: 2.5.0
|
|
90
|
+
ai_score: 85%
|
|
91
|
+
ai_confidence: HIGH
|
|
92
|
+
|
|
93
|
+
project:
|
|
94
|
+
name: my-project
|
|
95
|
+
goal: Build a CLI tool for data processing
|
|
96
|
+
|
|
97
|
+
instant_context:
|
|
98
|
+
what_building: CLI data processing tool
|
|
99
|
+
tech_stack: Python 3.11, Click, Pandas
|
|
100
|
+
key_files:
|
|
101
|
+
- src/cli.py
|
|
102
|
+
- src/processor.py
|
|
103
|
+
|
|
104
|
+
stack:
|
|
105
|
+
frontend: None
|
|
106
|
+
backend: Python
|
|
107
|
+
database: SQLite
|
|
108
|
+
infrastructure: Docker
|
|
109
|
+
|
|
110
|
+
human_context:
|
|
111
|
+
who: Data analysts
|
|
112
|
+
what: Process CSV files efficiently
|
|
113
|
+
why: Current tools are slow
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Type Definitions
|
|
117
|
+
|
|
118
|
+
The SDK provides typed access to all FAF sections:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from faf_sdk import (
|
|
122
|
+
FafData,
|
|
123
|
+
ProjectInfo,
|
|
124
|
+
StackInfo,
|
|
125
|
+
InstantContext,
|
|
126
|
+
ContextQuality,
|
|
127
|
+
HumanContext
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# All fields are optional except faf_version and project.name
|
|
131
|
+
faf = parse(content)
|
|
132
|
+
|
|
133
|
+
# Typed access
|
|
134
|
+
project: ProjectInfo = faf.data.project
|
|
135
|
+
stack: StackInfo = faf.data.stack
|
|
136
|
+
context: InstantContext = faf.data.instant_context
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Integration Example
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from faf_sdk import find_faf_file, parse_file, validate
|
|
143
|
+
|
|
144
|
+
def get_project_context():
|
|
145
|
+
"""Load project context for AI processing"""
|
|
146
|
+
path = find_faf_file()
|
|
147
|
+
if not path:
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
faf = parse_file(path)
|
|
151
|
+
result = validate(faf)
|
|
152
|
+
|
|
153
|
+
if not result.valid:
|
|
154
|
+
raise ValueError(f"Invalid FAF: {result.errors}")
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
"name": faf.data.project.name,
|
|
158
|
+
"goal": faf.data.project.goal,
|
|
159
|
+
"stack": faf.data.instant_context.tech_stack if faf.data.instant_context else None,
|
|
160
|
+
"key_files": faf.data.instant_context.key_files if faf.data.instant_context else [],
|
|
161
|
+
"score": faf.score,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Use in AI context
|
|
165
|
+
context = get_project_context()
|
|
166
|
+
if context:
|
|
167
|
+
print(f"Working on: {context['name']}")
|
|
168
|
+
print(f"Goal: {context['goal']}")
|
|
169
|
+
print(f"Tech: {context['stack']}")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Why FAF?
|
|
173
|
+
|
|
174
|
+
Every AI conversation starts from zero. No memory of your project. No understanding of your stack. Just vibes.
|
|
175
|
+
|
|
176
|
+
FAF solves this with a single, IANA-registered file that gives AI instant project context:
|
|
177
|
+
|
|
178
|
+
- **One file, one read, full understanding**
|
|
179
|
+
- **19ms average execution**
|
|
180
|
+
- **Zero setup friction**
|
|
181
|
+
- **MIT licensed, works everywhere**
|
|
182
|
+
|
|
183
|
+
## Links
|
|
184
|
+
|
|
185
|
+
- **Spec:** [github.com/Wolfe-Jam/faf](https://github.com/Wolfe-Jam/faf)
|
|
186
|
+
- **Site:** [faf.one](https://faf.one)
|
|
187
|
+
- **MCP Server:** [claude-faf-mcp](https://github.com/modelcontextprotocol/servers/tree/main/src/faf)
|
|
188
|
+
- **IANA Registration:** `application/vnd.faf+yaml`
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|