@donghyeonlee/jjamppong-harness 0.1.0
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.
- package/AGENTS.md +77 -0
- package/CONTEXT.md +51 -0
- package/README.md +85 -0
- package/bin/jjamppong.js +123 -0
- package/handoff.md +13 -0
- package/harness/contracts/capability-catalog.yaml +128 -0
- package/harness/contracts/gate-contract-matrix.yaml +188 -0
- package/harness/contracts/installer-contract.yaml +79 -0
- package/harness/contracts/ledger-event.schema.yaml +79 -0
- package/harness/contracts/path-policy.schema.yaml +51 -0
- package/harness/contracts/permission-decision.schema.yaml +95 -0
- package/harness/contracts/task.schema.yaml +88 -0
- package/harness/docs/adr/.gitkeep +1 -0
- package/harness/docs/adr/2026-06-02-jjamppong-planning-gate.md +33 -0
- package/harness/docs/agents/domain.md +14 -0
- package/harness/docs/agents/issue-tracker.md +9 -0
- package/harness/docs/agents/matt-pocock-skills.md +60 -0
- package/harness/docs/agents/triage-labels.md +11 -0
- package/harness/docs/solutions/.gitkeep +1 -0
- package/harness/docs/tasks/active/.gitkeep +1 -0
- package/harness/docs/tasks/archive/.gitkeep +1 -0
- package/harness/docs/tasks/archive/index.md +5 -0
- package/harness/docs/tasks/index.md +13 -0
- package/harness/doctor/doctor.js +114 -0
- package/harness/installer/install.js +235 -0
- package/harness/lifecycle/lifecycle.js +133 -0
- package/harness/permission/permission-decision.js +377 -0
- package/harness/release/CHECKSUMS.sha256 +84 -0
- package/harness/release/RELEASE-NOTES.md +33 -0
- package/harness/release/SOURCE-MANIFEST.md +31 -0
- package/harness/rules/module-types.md +98 -0
- package/harness/rules/rules.md +220 -0
- package/harness/rules/workflow.md +252 -0
- package/harness/state/compound.md +7 -0
- package/harness/state/intake.md +11 -0
- package/harness/state/module-structure.md +13 -0
- package/harness/state/planning.md +21 -0
- package/harness/templates/module/module-state.md +13 -0
- package/harness/templates/task/archive-summary.md +19 -0
- package/harness/templates/task/events.jsonl.template +1 -0
- package/harness/templates/task/gate-ledger.md +21 -0
- package/harness/templates/task/implementation-approval.md +11 -0
- package/harness/templates/task/planning/00-current-planning-context.md +3 -0
- package/harness/templates/task/planning/01-grill-summary.md +3 -0
- package/harness/templates/task/planning/02-research-summary.md +3 -0
- package/harness/templates/task/planning/02b-compound-lookup.md +3 -0
- package/harness/templates/task/planning/02c-architecture-orientation.md +3 -0
- package/harness/templates/task/planning/03-prd.md +3 -0
- package/harness/templates/task/planning/04-issues.md +3 -0
- package/harness/templates/task/planning/05-module-structure.md +3 -0
- package/harness/templates/task/planning/06-writing-plan.md +3 -0
- package/harness/templates/task/planning/07-plan-review.md +3 -0
- package/harness/templates/task/planning-pack.md +23 -0
- package/harness/templates/task/task.yaml +10 -0
- package/harness/templates/task/verification.md +12 -0
- package/harness/verify/verify.js +271 -0
- package/module-template/MODULE.md +25 -0
- package/module-template/README.md +9 -0
- package/modules/.gitkeep +0 -0
- package/package.json +40 -0
- package/proposals/README.md +16 -0
- package/scripts/install-jjamppong-harness.ps1 +62 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
version: 0.1.0
|
|
2
|
+
name: installer-contract
|
|
3
|
+
|
|
4
|
+
modes:
|
|
5
|
+
install:
|
|
6
|
+
behavior: install_verify_stop
|
|
7
|
+
may_modify: [harness_core_files, state_neutral_files, harness_lock]
|
|
8
|
+
must_not: [start_planning, create_product_task, create_code, run_live_access, commit, push]
|
|
9
|
+
verify:
|
|
10
|
+
behavior: read_only_pass_fail
|
|
11
|
+
doctor:
|
|
12
|
+
behavior: read_only_diagnose_plus_proposal
|
|
13
|
+
live_edit_default: false
|
|
14
|
+
update:
|
|
15
|
+
behavior: proposal_only_if_managed_files_modified
|
|
16
|
+
repair:
|
|
17
|
+
behavior: proposal_only_if_managed_files_modified
|
|
18
|
+
|
|
19
|
+
ownership_classes:
|
|
20
|
+
harness_core_owned:
|
|
21
|
+
examples: [AGENTS.md, harness/rules/**, harness/contracts/**, scripts/install-jjamppong-harness.ps1]
|
|
22
|
+
update_strategy: replace_with_backup_if_clean_else_proposal
|
|
23
|
+
project_overlay_owned:
|
|
24
|
+
examples: [project-local policy files]
|
|
25
|
+
update_strategy: merge_proposal
|
|
26
|
+
user_owned:
|
|
27
|
+
update_strategy: never_overwrite
|
|
28
|
+
generated_derived:
|
|
29
|
+
examples: [task.yaml, gate-ledger.md projection, index files]
|
|
30
|
+
update_strategy: regenerate_from_canonical_when_explicit
|
|
31
|
+
append_only_canonical:
|
|
32
|
+
examples: [events.jsonl]
|
|
33
|
+
update_strategy: append_only_never_rewrite_without_repair_record
|
|
34
|
+
local_artifact:
|
|
35
|
+
examples: [harness/artifacts/local/**]
|
|
36
|
+
update_strategy: gitignored_do_not_publish
|
|
37
|
+
|
|
38
|
+
fresh_install_requirements:
|
|
39
|
+
root_items:
|
|
40
|
+
- AGENTS.md
|
|
41
|
+
- README.md
|
|
42
|
+
- CONTEXT.md
|
|
43
|
+
- handoff.md
|
|
44
|
+
- harness/
|
|
45
|
+
- modules/
|
|
46
|
+
- module-template/
|
|
47
|
+
- proposals/
|
|
48
|
+
- harness.lock.yaml
|
|
49
|
+
forbidden_nested:
|
|
50
|
+
- jjamppong-harness/
|
|
51
|
+
- ourosuper-harness/
|
|
52
|
+
state:
|
|
53
|
+
active_tasks_empty: true
|
|
54
|
+
archive_empty_or_gitkeep_only: true
|
|
55
|
+
planning_state: neutral
|
|
56
|
+
handoff: neutral
|
|
57
|
+
git:
|
|
58
|
+
origin_must_not_be_template_repo: true
|
|
59
|
+
create_remote_repo_default: false
|
|
60
|
+
commit_default: false
|
|
61
|
+
push_default: false
|
|
62
|
+
|
|
63
|
+
backup_rollback:
|
|
64
|
+
backup_before_overwrite: true
|
|
65
|
+
rollback_manifest_required: true
|
|
66
|
+
idempotent_install_required: true
|
|
67
|
+
|
|
68
|
+
harness_lock_required_fields:
|
|
69
|
+
- harness.name
|
|
70
|
+
- harness.version
|
|
71
|
+
- installer.package
|
|
72
|
+
- installer.version
|
|
73
|
+
- installed_at
|
|
74
|
+
- installed_from
|
|
75
|
+
- planning_started
|
|
76
|
+
- github_repo_created
|
|
77
|
+
- commit_created
|
|
78
|
+
- push_performed
|
|
79
|
+
- managed_files
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
version: 0.1.0
|
|
2
|
+
name: ledger-event-schema
|
|
3
|
+
canonical_log: events.jsonl
|
|
4
|
+
append_only: true
|
|
5
|
+
hash_chain_required: true
|
|
6
|
+
|
|
7
|
+
required_fields:
|
|
8
|
+
- event_id
|
|
9
|
+
- schema_version
|
|
10
|
+
- task_id
|
|
11
|
+
- event_type
|
|
12
|
+
- created_at
|
|
13
|
+
- actor_type
|
|
14
|
+
- previous_hash
|
|
15
|
+
- event_hash
|
|
16
|
+
|
|
17
|
+
fields:
|
|
18
|
+
event_id: {type: string, format: uuid_or_ulid}
|
|
19
|
+
schema_version: {type: string}
|
|
20
|
+
task_id: {type: string}
|
|
21
|
+
event_type:
|
|
22
|
+
enum:
|
|
23
|
+
- task_opened
|
|
24
|
+
- gate_question
|
|
25
|
+
- user_answer
|
|
26
|
+
- approval_decision
|
|
27
|
+
- gate_status_change
|
|
28
|
+
- artifact_written
|
|
29
|
+
- permission_decision
|
|
30
|
+
- capability_used
|
|
31
|
+
- verification_result
|
|
32
|
+
- invalidation
|
|
33
|
+
- projection_generated
|
|
34
|
+
- task_archived
|
|
35
|
+
created_at: {type: string, format: iso8601}
|
|
36
|
+
actor_type:
|
|
37
|
+
enum: [user, assistant, tool, verifier, doctor, installer, reviewer]
|
|
38
|
+
actor_id: {type: string, required: false}
|
|
39
|
+
previous_hash: {type: string}
|
|
40
|
+
event_hash: {type: string}
|
|
41
|
+
payload: {type: object}
|
|
42
|
+
|
|
43
|
+
payload_schemas:
|
|
44
|
+
gate_question:
|
|
45
|
+
required: [gate_id, question_text, explicit_scope, still_forbidden]
|
|
46
|
+
fields:
|
|
47
|
+
gate_id: {type: string}
|
|
48
|
+
question_text: {type: string}
|
|
49
|
+
explicit_scope: {type: object}
|
|
50
|
+
still_forbidden: {type: array}
|
|
51
|
+
target_paths: {type: array, required: false}
|
|
52
|
+
capability_flags: {type: object, required: false}
|
|
53
|
+
user_answer:
|
|
54
|
+
required: [answer_quote, responds_to_event_id]
|
|
55
|
+
fields:
|
|
56
|
+
answer_quote: {type: string}
|
|
57
|
+
responds_to_event_id: {type: string}
|
|
58
|
+
approval_decision:
|
|
59
|
+
required: [gate_id, user_answer_event_id, gate_question_event_id, interpreted_scope, effects, invalidates_on]
|
|
60
|
+
fields:
|
|
61
|
+
gate_id: {type: string}
|
|
62
|
+
status: {enum: [approved, rejected, blocked, not_applicable, invalidated]}
|
|
63
|
+
interpreted_scope: {type: object}
|
|
64
|
+
effects: {type: object}
|
|
65
|
+
based_on_artifact_hashes: {type: object}
|
|
66
|
+
target_paths: {type: object}
|
|
67
|
+
still_forbidden: {type: array}
|
|
68
|
+
invalidates_on: {type: array}
|
|
69
|
+
permission_decision:
|
|
70
|
+
required: [decision_id, capability, decision, reason, based_on_events]
|
|
71
|
+
fields:
|
|
72
|
+
decision_id: {type: string}
|
|
73
|
+
capability: {type: string}
|
|
74
|
+
path: {type: string, required: false}
|
|
75
|
+
target: {type: string, required: false}
|
|
76
|
+
decision: {enum: [allow, deny, block, proposal_required]}
|
|
77
|
+
reason: {type: string}
|
|
78
|
+
required_next_action: {type: object, required: false}
|
|
79
|
+
based_on_events: {type: array}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
version: 0.1.0
|
|
2
|
+
name: path-policy-schema
|
|
3
|
+
|
|
4
|
+
normalization_required:
|
|
5
|
+
- expand_user_visible_windows_drive_shorthand
|
|
6
|
+
- normalize_separators
|
|
7
|
+
- resolve_dot_segments
|
|
8
|
+
- convert_to_absolute_path
|
|
9
|
+
- resolve_realpath
|
|
10
|
+
- case_normalize_when_filesystem_is_case_insensitive
|
|
11
|
+
- detect_symlink
|
|
12
|
+
- detect_junction
|
|
13
|
+
- detect_hardlink_when_possible
|
|
14
|
+
- reject_alternate_data_streams_on_windows
|
|
15
|
+
- reject_reserved_device_names_on_windows
|
|
16
|
+
|
|
17
|
+
windows_cases:
|
|
18
|
+
drive_shorthand:
|
|
19
|
+
example: F:mptech
|
|
20
|
+
policy: normalize_to_explicit_drive_root_or_ask_if_ambiguous
|
|
21
|
+
unc_paths:
|
|
22
|
+
example: "\\\\server\\share"
|
|
23
|
+
policy: deny_unless_project_root_explicitly_unc
|
|
24
|
+
alternate_data_stream:
|
|
25
|
+
example: file.txt:stream
|
|
26
|
+
policy: deny
|
|
27
|
+
reserved_names:
|
|
28
|
+
examples: [CON, NUL, AUX, PRN]
|
|
29
|
+
policy: deny
|
|
30
|
+
symlink_junction_escape:
|
|
31
|
+
policy: deny_if_realpath_outside_project_root_or_outside_approved_module
|
|
32
|
+
|
|
33
|
+
glob_policy:
|
|
34
|
+
raw_globs_do_not_grant_permission: true
|
|
35
|
+
glob_must_expand_to_exact_paths_before_decision: true
|
|
36
|
+
empty_glob: deny
|
|
37
|
+
glob_with_escape: deny
|
|
38
|
+
|
|
39
|
+
containment:
|
|
40
|
+
project_root:
|
|
41
|
+
required_for_all_repo_writes: true
|
|
42
|
+
modules_root:
|
|
43
|
+
default_product_code_root: modules/
|
|
44
|
+
path_decision_uses: realpath
|
|
45
|
+
harness_core_paths:
|
|
46
|
+
- AGENTS.md
|
|
47
|
+
- harness/rules/**
|
|
48
|
+
- harness/contracts/**
|
|
49
|
+
- scripts/install-jjamppong-harness.ps1
|
|
50
|
+
- plugins/**
|
|
51
|
+
- package installer files
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
version: 0.1.0
|
|
2
|
+
name: permission-decision-schema
|
|
3
|
+
|
|
4
|
+
required_fields:
|
|
5
|
+
- decision_id
|
|
6
|
+
- schema_version
|
|
7
|
+
- task_id
|
|
8
|
+
- requested_action
|
|
9
|
+
- capability
|
|
10
|
+
- decision
|
|
11
|
+
- reason
|
|
12
|
+
- based_on
|
|
13
|
+
- created_at
|
|
14
|
+
|
|
15
|
+
decisions:
|
|
16
|
+
- allow
|
|
17
|
+
- deny
|
|
18
|
+
- block
|
|
19
|
+
- proposal_required
|
|
20
|
+
|
|
21
|
+
requested_action_fields:
|
|
22
|
+
action_type:
|
|
23
|
+
enum:
|
|
24
|
+
- file_read
|
|
25
|
+
- file_write
|
|
26
|
+
- file_delete
|
|
27
|
+
- command_exec
|
|
28
|
+
- network_access
|
|
29
|
+
- package_install
|
|
30
|
+
- git_operation
|
|
31
|
+
- installer_operation
|
|
32
|
+
- harness_core_change
|
|
33
|
+
- parallel_write
|
|
34
|
+
path: {type: string, required: false}
|
|
35
|
+
command: {type: string, required: false}
|
|
36
|
+
network_target: {type: string, required: false}
|
|
37
|
+
package_name: {type: string, required: false}
|
|
38
|
+
|
|
39
|
+
capability_examples:
|
|
40
|
+
file_write_module: file.write.module
|
|
41
|
+
live_target: network.live_target
|
|
42
|
+
package_install: package.install
|
|
43
|
+
git_push: git.push
|
|
44
|
+
secret_read: file.read.secret
|
|
45
|
+
|
|
46
|
+
based_on:
|
|
47
|
+
required:
|
|
48
|
+
- canonical_event_log_hash
|
|
49
|
+
- relevant_event_ids
|
|
50
|
+
- artifact_hashes
|
|
51
|
+
- contract_versions
|
|
52
|
+
fields:
|
|
53
|
+
canonical_event_log_hash: string
|
|
54
|
+
relevant_event_ids: array
|
|
55
|
+
artifact_hashes: object
|
|
56
|
+
contract_versions: object
|
|
57
|
+
|
|
58
|
+
path_policy_result:
|
|
59
|
+
required_when: path_present
|
|
60
|
+
fields:
|
|
61
|
+
raw_path: string
|
|
62
|
+
normalized_path: string
|
|
63
|
+
absolute_path: string
|
|
64
|
+
realpath: string
|
|
65
|
+
project_root: string
|
|
66
|
+
is_within_project_root: boolean
|
|
67
|
+
is_within_modules: boolean
|
|
68
|
+
has_symlink_or_junction: boolean
|
|
69
|
+
matched_allowed_pattern: string
|
|
70
|
+
escape_detected: boolean
|
|
71
|
+
|
|
72
|
+
required_next_action:
|
|
73
|
+
fields:
|
|
74
|
+
type:
|
|
75
|
+
enum: [ask_user, open_gate, create_proposal, run_verify, stop]
|
|
76
|
+
gate_id: string
|
|
77
|
+
suggested_user_question: string
|
|
78
|
+
missing_capabilities: array
|
|
79
|
+
|
|
80
|
+
invalidation:
|
|
81
|
+
approval_must_bind_to:
|
|
82
|
+
- gate_question_event_id
|
|
83
|
+
- user_answer_event_id
|
|
84
|
+
- target_paths
|
|
85
|
+
- capability_flags
|
|
86
|
+
- artifact_hashes
|
|
87
|
+
invalidates_when:
|
|
88
|
+
- prd_hash_changed
|
|
89
|
+
- issues_hash_changed
|
|
90
|
+
- module_structure_hash_changed
|
|
91
|
+
- writing_plan_hash_changed
|
|
92
|
+
- target_paths_changed
|
|
93
|
+
- capability_need_added
|
|
94
|
+
- user_added_new_constraint
|
|
95
|
+
- contract_version_changed
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
version: 0.1.0
|
|
2
|
+
name: task-schema
|
|
3
|
+
|
|
4
|
+
canonical_event_log: events.jsonl
|
|
5
|
+
human_projection: gate-ledger.md
|
|
6
|
+
cache_projection: task.yaml
|
|
7
|
+
|
|
8
|
+
allowed_task_types:
|
|
9
|
+
- install
|
|
10
|
+
- module_bootstrap
|
|
11
|
+
- product_feature
|
|
12
|
+
- product_bugfix
|
|
13
|
+
- template_maintenance
|
|
14
|
+
- project_policy_change
|
|
15
|
+
- harness_update
|
|
16
|
+
- knowledge_maintenance
|
|
17
|
+
- archive_maintenance
|
|
18
|
+
|
|
19
|
+
task_types:
|
|
20
|
+
module_bootstrap:
|
|
21
|
+
purpose: Create module workspace only.
|
|
22
|
+
allowed_capabilities:
|
|
23
|
+
- file.write.folder_skeleton
|
|
24
|
+
- file.write.task_artifact
|
|
25
|
+
denied_capabilities:
|
|
26
|
+
- file.write.module_executable_source
|
|
27
|
+
- tests.create
|
|
28
|
+
- fixtures.create
|
|
29
|
+
- package.install
|
|
30
|
+
- network.live_target
|
|
31
|
+
- git.commit
|
|
32
|
+
- git.push
|
|
33
|
+
allowed_files:
|
|
34
|
+
- directories
|
|
35
|
+
- .gitkeep
|
|
36
|
+
- MODULE.md
|
|
37
|
+
- README.md
|
|
38
|
+
- module-state.md
|
|
39
|
+
denied_files:
|
|
40
|
+
- "*.py"
|
|
41
|
+
- "*.ts"
|
|
42
|
+
- "*.js"
|
|
43
|
+
- "*.ps1"
|
|
44
|
+
- "*.sh"
|
|
45
|
+
- tests/**
|
|
46
|
+
- fixtures/**
|
|
47
|
+
- package.json
|
|
48
|
+
- pyproject.toml
|
|
49
|
+
- executable runtime config
|
|
50
|
+
|
|
51
|
+
product_feature:
|
|
52
|
+
purpose: Implement approved vertical slice inside approved module paths.
|
|
53
|
+
requires:
|
|
54
|
+
- grill
|
|
55
|
+
- research
|
|
56
|
+
- prd
|
|
57
|
+
- issues
|
|
58
|
+
- module_structure
|
|
59
|
+
- writing_plan
|
|
60
|
+
- plan_review
|
|
61
|
+
- implementation
|
|
62
|
+
default_root: modules/
|
|
63
|
+
|
|
64
|
+
template_maintenance:
|
|
65
|
+
purpose: Change harness-core rules/contracts/installer/plugins.
|
|
66
|
+
requires:
|
|
67
|
+
- proposal_approved
|
|
68
|
+
- separate_template_maintenance_checkout
|
|
69
|
+
forbidden:
|
|
70
|
+
- product_code
|
|
71
|
+
- project_domain_solution_as_core_rule_without_proposal
|
|
72
|
+
|
|
73
|
+
project_policy_change:
|
|
74
|
+
purpose: Change project-local policy only.
|
|
75
|
+
requires:
|
|
76
|
+
- project_policy_proposal
|
|
77
|
+
forbidden:
|
|
78
|
+
- harness_core_rule_change
|
|
79
|
+
|
|
80
|
+
projections:
|
|
81
|
+
task_yaml:
|
|
82
|
+
status: derived_cache
|
|
83
|
+
may_be_regenerated: true
|
|
84
|
+
cannot_grant_permission: true
|
|
85
|
+
gate_ledger_md:
|
|
86
|
+
status: human_projection
|
|
87
|
+
may_be_regenerated: true
|
|
88
|
+
cannot_grant_permission_without_events: true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# keep
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# ADR: Use 짬뽕하네스 Planning Gate
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted after proposal approval.
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
The previous harness centered planning on OuroSuper interview, Seed YAML, and handoff-packet concepts. That flow made the harness depend on a planning runtime and produced confusion around missing ambiguity scores, duplicated handoff meanings, and scattered AI artifacts.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Use 짬뽕하네스 as the harness workflow. The planning gate combines Matt Pocock planning skills, Superpowers writing plans, gstack review, Compound Engineering learning, and vowline discipline.
|
|
14
|
+
|
|
15
|
+
AI task artifacts live under `harness/docs/tasks/active/<slug>/` while in progress and move to `harness/docs/tasks/archive/<slug>/` after completion by default. Long-lived reusable learning lives under `harness/docs/solutions/`. `harness/state/` stores only small pointer/status files.
|
|
16
|
+
|
|
17
|
+
## Alternatives Considered
|
|
18
|
+
|
|
19
|
+
- Keep OuroSuper as the planning engine.
|
|
20
|
+
- Store AI artifacts under root `docs/`.
|
|
21
|
+
- Put reusable solutions under `harness/state/`.
|
|
22
|
+
- Restore a small-task bypass.
|
|
23
|
+
|
|
24
|
+
## Consequences
|
|
25
|
+
|
|
26
|
+
- The workflow is more explicit and easier to audit.
|
|
27
|
+
- Every task creates more planning artifacts.
|
|
28
|
+
- The user reviews one active task folder during work, then mostly works from `modules/` after approval.
|
|
29
|
+
- Root `handoff.md` keeps its original next-chat role.
|
|
30
|
+
|
|
31
|
+
## Rollback
|
|
32
|
+
|
|
33
|
+
Reintroduce a proposal that restores the previous workflow and updates `harness/rules/`, README, and AGENTS.md together. Do not partially restore OuroSuper terms without restoring the full old workflow.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Domain Docs
|
|
2
|
+
|
|
3
|
+
This harness uses a single-context documentation layout.
|
|
4
|
+
|
|
5
|
+
Required files:
|
|
6
|
+
|
|
7
|
+
- Root glossary: `CONTEXT.md`
|
|
8
|
+
- Architecture decisions: `harness/docs/adr/`
|
|
9
|
+
|
|
10
|
+
Consumer rules:
|
|
11
|
+
|
|
12
|
+
- `CONTEXT.md` is a glossary, not a PRD or scratch pad.
|
|
13
|
+
- ADRs are for decisions that are hard to reverse, surprising without context, and chosen after a real trade-off.
|
|
14
|
+
- Do not create ADRs for routine implementation details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Issue Tracker
|
|
2
|
+
|
|
3
|
+
This harness uses local markdown task issues by default.
|
|
4
|
+
|
|
5
|
+
Issues live under `harness/docs/tasks/active/<YYYY-MM-DD-short-topic>/issues/`.
|
|
6
|
+
|
|
7
|
+
Each issue is a vertical slice that can be reviewed or implemented independently.
|
|
8
|
+
|
|
9
|
+
Do not publish issues to GitHub Issues unless the user explicitly asks for that in the current chat.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Matt Pocock Skills
|
|
2
|
+
|
|
3
|
+
짬뽕하네스 requires these external Matt Pocock skills:
|
|
4
|
+
|
|
5
|
+
- `setup-matt-pocock-skills`
|
|
6
|
+
- `grill-with-docs`
|
|
7
|
+
- `to-prd`
|
|
8
|
+
- `to-issues`
|
|
9
|
+
|
|
10
|
+
## Readiness Check
|
|
11
|
+
|
|
12
|
+
Before the planning gate continues, the agent must verify that the required skills are available in the current Codex skill list or installed skill directories.
|
|
13
|
+
|
|
14
|
+
Use this readiness command in PowerShell when the visible skill list is unavailable:
|
|
15
|
+
|
|
16
|
+
```powershell
|
|
17
|
+
$required = @(
|
|
18
|
+
'setup-matt-pocock-skills',
|
|
19
|
+
'grill-with-docs',
|
|
20
|
+
'to-prd',
|
|
21
|
+
'to-issues'
|
|
22
|
+
)
|
|
23
|
+
$roots = @(
|
|
24
|
+
(Join-Path $env:USERPROFILE '.codex/skills'),
|
|
25
|
+
(Join-Path $env:USERPROFILE '.agents/skills')
|
|
26
|
+
)
|
|
27
|
+
$skillFiles = foreach ($root in $roots) {
|
|
28
|
+
if (Test-Path -LiteralPath $root) {
|
|
29
|
+
Get-ChildItem -LiteralPath $root -Recurse -Filter 'SKILL.md' -ErrorAction SilentlyContinue
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
$missing = foreach ($skill in $required) {
|
|
33
|
+
$found = $skillFiles | Where-Object {
|
|
34
|
+
Select-String -LiteralPath $_.FullName -Pattern "name: $skill" -Quiet
|
|
35
|
+
}
|
|
36
|
+
if (-not $found) { $skill }
|
|
37
|
+
}
|
|
38
|
+
if ($missing) {
|
|
39
|
+
$missing
|
|
40
|
+
throw "Missing required Matt Pocock planning skills"
|
|
41
|
+
}
|
|
42
|
+
"OK: all Matt Pocock planning skills available"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If any required skill is unavailable, stop and tell the user:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
Matt Pocock planning skills are required before this harness can continue.
|
|
49
|
+
Install them first, then rerun this task.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Install Reference
|
|
53
|
+
|
|
54
|
+
Use the official installer when available:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx skills@latest add mattpocock/skills
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Do not vendor-copy the skill files into this repository.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Triage Labels
|
|
2
|
+
|
|
3
|
+
Local markdown issues use these canonical roles:
|
|
4
|
+
|
|
5
|
+
- `needs-triage` - maintainer needs to evaluate
|
|
6
|
+
- `needs-info` - waiting on user input
|
|
7
|
+
- `ready-for-agent` - ready for AFK agent work
|
|
8
|
+
- `ready-for-human` - requires human judgment or external access
|
|
9
|
+
- `wontfix` - will not be actioned
|
|
10
|
+
|
|
11
|
+
For local markdown issues, record the role in the issue body instead of applying a GitHub label.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# keep
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# keep
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# keep
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Task Index
|
|
2
|
+
|
|
3
|
+
Active tasks are read directly from `harness/docs/tasks/active/`.
|
|
4
|
+
|
|
5
|
+
Archived tasks are cold context. Read archive indexes and summaries before opening detailed artifacts.
|
|
6
|
+
|
|
7
|
+
## Active
|
|
8
|
+
|
|
9
|
+
- See `active/`
|
|
10
|
+
|
|
11
|
+
## Archive
|
|
12
|
+
|
|
13
|
+
- See `archive/`
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { verifyRoot } = require('../verify/verify');
|
|
7
|
+
|
|
8
|
+
function parseArgs(argv) {
|
|
9
|
+
const args = {};
|
|
10
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
11
|
+
const token = argv[i];
|
|
12
|
+
if (!token.startsWith('--')) continue;
|
|
13
|
+
const key = token.slice(2);
|
|
14
|
+
const next = argv[i + 1];
|
|
15
|
+
if (!next || next.startsWith('--')) {
|
|
16
|
+
args[key] = true;
|
|
17
|
+
} else {
|
|
18
|
+
args[key] = next;
|
|
19
|
+
i += 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return args;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function nextActionFor(failure) {
|
|
26
|
+
const table = {
|
|
27
|
+
missing_root_item: 'Run installer or restore the missing root file before planning.',
|
|
28
|
+
missing_contract: 'Restore harness/contracts from the release package.',
|
|
29
|
+
nested_harness_folder: 'Move harness files to the project root; do not keep a nested template clone.',
|
|
30
|
+
secret_file_present: 'Do not read the value. Move/ignore the secret outside publishable harness scope.',
|
|
31
|
+
harness_lock_missing_field: 'Regenerate harness.lock.yaml from installer receipt data.',
|
|
32
|
+
planning_started_during_install: 'Treat install as contaminated; create a repair proposal and reset install-only state.',
|
|
33
|
+
github_repo_created_during_install: 'Record as policy violation; future installer defaults must not create remote repos.',
|
|
34
|
+
commit_created_during_install: 'Stop and ask for git cleanup instructions; do not rewrite history automatically.',
|
|
35
|
+
push_performed_during_install: 'Stop and ask for remote cleanup instructions; do not mutate remote automatically.',
|
|
36
|
+
active_task_single_default: 'Archive, cancel, or explicitly approve parallel active task handling.',
|
|
37
|
+
projection_without_canonical_event: 'Regenerate projections from events.jsonl or ask the user for explicit approval again.',
|
|
38
|
+
event_hash_chain_broken: 'Stop using this task state until the event log is audited; do not invent missing approvals.',
|
|
39
|
+
event_required_fields: 'Repair event log only from trusted source events.',
|
|
40
|
+
};
|
|
41
|
+
return table[failure.id] || 'Create a proposal explaining the required safe repair.';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function createProposal(root, verifyResult) {
|
|
45
|
+
const proposalDir = path.join(root, 'proposals', 'active');
|
|
46
|
+
fs.mkdirSync(proposalDir, { recursive: true });
|
|
47
|
+
const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\..+$/, 'Z');
|
|
48
|
+
const proposalPath = path.join(proposalDir, `doctor-fix-${stamp}.md`);
|
|
49
|
+
const lines = [
|
|
50
|
+
'# Doctor Repair Proposal',
|
|
51
|
+
'',
|
|
52
|
+
'This proposal was generated by `harness/doctor/doctor.js --proposal`.',
|
|
53
|
+
'It does not apply live repairs.',
|
|
54
|
+
'',
|
|
55
|
+
'## Failures',
|
|
56
|
+
'',
|
|
57
|
+
];
|
|
58
|
+
for (const failure of verifyResult.failures) {
|
|
59
|
+
lines.push(`- ${failure.id}: ${failure.message}`);
|
|
60
|
+
lines.push(` - Suggested next action: ${nextActionFor(failure)}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
lines.push('## Required Approval');
|
|
64
|
+
lines.push('');
|
|
65
|
+
lines.push('A user must approve any live file change separately. This proposal does not grant implementation, git, package, network, or harness-core write permission.');
|
|
66
|
+
fs.writeFileSync(proposalPath, `${lines.join('\n')}\n`, 'utf8');
|
|
67
|
+
return proposalPath;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function diagnose(root, options = {}) {
|
|
71
|
+
const result = verifyRoot(root);
|
|
72
|
+
const diagnosis = {
|
|
73
|
+
ok: result.ok,
|
|
74
|
+
root: result.root,
|
|
75
|
+
failures: result.failures.map((failure) => ({
|
|
76
|
+
...failure,
|
|
77
|
+
next_action: nextActionFor(failure),
|
|
78
|
+
})),
|
|
79
|
+
warnings: result.warnings,
|
|
80
|
+
proposal_path: null,
|
|
81
|
+
};
|
|
82
|
+
if (!result.ok && options.proposal) {
|
|
83
|
+
diagnosis.proposal_path = createProposal(result.root, result);
|
|
84
|
+
}
|
|
85
|
+
return diagnosis;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function main() {
|
|
89
|
+
const args = parseArgs(process.argv.slice(2));
|
|
90
|
+
const root = path.resolve(args.root || process.cwd());
|
|
91
|
+
const result = diagnose(root, { proposal: Boolean(args.proposal) });
|
|
92
|
+
if (args.json) {
|
|
93
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
94
|
+
} else if (result.ok) {
|
|
95
|
+
process.stdout.write(`doctor found no P0 issues for ${result.root}\n`);
|
|
96
|
+
} else {
|
|
97
|
+
process.stdout.write(`doctor found ${result.failures.length} issue(s) for ${result.root}\n`);
|
|
98
|
+
for (const failure of result.failures) {
|
|
99
|
+
process.stdout.write(`- ${failure.id}: ${failure.next_action}\n`);
|
|
100
|
+
}
|
|
101
|
+
if (result.proposal_path) {
|
|
102
|
+
process.stdout.write(`proposal: ${result.proposal_path}\n`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (require.main === module) {
|
|
109
|
+
main();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
diagnose,
|
|
114
|
+
};
|