Plexum-side counterpart to HarborForge.OpenclawPlugin. Pins to the
plugin repo's main branch (initial commit). Tracked separately from
HarborForge.OpenclawPlugin — the two plugins run side by side during
the OpenClaw → Plexum migration window.
Operator install:
cd HarborForge.PlexumPlugin
bash scripts/install.sh
writes a binary + manifest into ~/.plexum/plugins/harbor-forge/.
* HarborForge.Backend 595391b → 01f6b56
fix(bootstrap): seed member.remove + schedule_type.read + schedule_type.manage
into DEFAULT_PERMISSIONS — code enforced them but Role Editor couldn't
show them. No default-role changes.
prod hf_backend v0.4.3 live; the 3 rows are now in the permissions
table on t1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* HarborForge.Backend 54feb96 → 595391b
feat(users): auto-default agent accounts to general-agent role
(POST /users with agent_id sets role=general-agent, was guest).
Also seeds general-agent in init_bootstrap _DEFAULT_ROLES.
* HarborForge.Frontend 766474f → 04bb0c6
feat(role-editor): "Use as template" — copy another role's perm set
Pick from dropdown → click button → replaces all checkboxes locally
(save still required to persist).
prod cutover: hf_backend v0.4.2 + hf_frontend v0.4.3 live on t1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* HarborForge.Frontend 10771a8 → f587e1e
fix(frontend): drop localStorage HF_BACKEND_BASE_URL; env-only.
Fixes new-browser blank MonitorPage / api 404 after v0.4.0 wizard removal
(api.ts + useAuthConfig still had the old localStorage path; App.tsx had
been refactored but those two were missed). All 3 read sites now read
import.meta.env.VITE_HF_BACKEND_BASE_URL only.
prod is on frontend v0.4.1 with this fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* HarborForge.Backend 5ea2cdf → 54feb96
fix(cli): import all model modules so SA relationship resolution works
(hf-cli admin list crashed with KeyError: Agent on prod cutover, fixed
by mirroring main.py's startup() bulk-import in cli/__main__.py).
prod is on v0.4.1 with this fix in place.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match the language of the submodule READMEs; content unchanged
(structure, tables, links, ports, security notes preserved).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sync umbrella refs after merging the README refresh (all submodules),
backend security hardening, and frontend Foundry Deck redesign into
their respective mains.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrite top-level README (full 7-submodule map, corrected architecture/
ports/model, security notes). No conflicts: remote commits touched only
submodule pointers, this branch only README.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
List all 7 submodules with stack/role, correct architecture and ports,
replace stale Issues model with tasks/milestones/proposals, add Security
notes (mandatory strong SECRET_KEY) and cross-links to component READMEs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- FE-PR-003: Essential create/edit modal with type selector and partial refresh already implemented in ProposalDetailPage
- FE-PR-004: Accept modal with milestone selector and generated tasks display already implemented
- FE-PR-005: Remove 'story' from TASK_TYPES in CreateTaskPage and CreateTaskModal - all story/* must come from Proposal Accept workflow
- PATCH /calendar/plans/{plan_id}: edit a recurring schedule plan
- Validates period-parameter hierarchy after merge
- Rejects edits to inactive (cancelled) plans
- Detaches future materialized slots so they keep old data
- Past materialized slots remain untouched
- POST /calendar/plans/{plan_id}/cancel: cancel (soft-delete) a plan
- Sets is_active=False
- Detaches future materialized slots (plan_id -> NULL)
- Preserves past materialized slots, returns their IDs
- Added SchedulePlanEdit and SchedulePlanCancelResponse schemas
- Imported guard_plan_edit/cancel_no_past_retroaction from slot_immutability
- Add POST /calendar/slots/{slot_id}/cancel for real slot cancellation
- Add POST /calendar/slots/virtual/{virtual_id}/cancel for virtual slot cancellation
- Virtual cancel materializes the slot first, then marks as Skipped
- Both endpoints enforce past-slot immutability guard
- Both endpoints detach from plan (set plan_id=NULL)
- Status set to SlotStatus.SKIPPED on cancel
- Add TimeSlotCancelResponse schema
- Import guard_cancel_real_slot and guard_cancel_virtual_slot
- Add GET /calendar/day endpoint with optional ?date= query param
- Returns unified CalendarDayResponse merging real slots + virtual plan slots
- New CalendarSlotItem schema supports both real (id) and virtual (virtual_id) slots
- Excludes inactive slots (skipped/aborted) from results
- All slots sorted by scheduled_at ascending
- Add TimeSlotCreate, TimeSlotResponse, TimeSlotCreateResponse schemas
- Add SlotConflictItem, SlotTypeEnum, EventTypeEnum, SlotStatusEnum to schemas
- Add POST /calendar/slots endpoint with:
- Overlap detection (409 on conflict)
- Workload warning computation (advisory, returned in response)
- Support for event_type + event_data (job/system/entertainment)
- Default date to today if not provided
- Add _slot_to_response helper for ORM -> schema conversion
- Virtual slot ID: plan-{plan_id}-{YYYY-MM-DD} format with parse/make helpers
- Plan-date matching: on_month/on_week/on_day hierarchy with week_of_month calc
- Materialization: convert virtual slot to real TimeSlot row, copy plan template
- Detach: clear plan_id after edit/cancel to break plan association
- Bulk materialization: materialize_all_for_date for daily pre-compute
- 23 tests covering all paths (matching, virtual gen, materialize, detach, bulk)
Decision: retain DB column, mark DEPRECATED. Existing rows still return
feat_task_id via API. New accept flow (BE-PR-007) does not write it.
Clients should migrate to generated_tasks / Task.source_proposal_id.
- Backend: model/schema/router deprecation comments updated
- Backend: added docs/BE-PR-010-feat-task-id-deprecation.md
- Tests: updated to work with Essential-based accept flow
- Tests: all 21 proposal tests pass
- TASKLIST: BE-PR-010 marked complete
- New router: /projects/{project_id}/proposals/{proposal_id}/essentials
- GET (list) - list all essentials under a proposal
- POST (create) - create essential with auto-generated EssentialCode
- GET /{id} - get single essential by id or essential_code
- PATCH /{id} - update essential (title, type, description)
- DELETE /{id} - delete essential
- All mutations restricted to open proposals only
- Permission: creator, project owner, or global admin
- Registered essentials router in main.py
- Updated GET /proposals/{id} to return ProposalDetailResponse with
embedded essentials list
- Activity logging on all CRUD operations
- Add comprehensive docstring to Proposal model documenting all relationships
- Add column comments for all fields (title, description, status, project_id, etc.)
- Mark feat_task_id as DEPRECATED (will be replaced by Essential→task mapping in BE-PR-008)
- Add proposal_code hybrid property as preferred alias for DB column propose_code
- Update ProposalResponse schema to include proposal_code alongside propose_code
- Update serializer to emit both proposal_code and propose_code for backward compat
- No DB migration needed — only Python-level changes
- Backend: new canonical Proposal model + /proposals router
- Backward-compat shims for old Propose imports and /proposes API
- Tests updated to use /proposals, legacy compat tests added
- Impact checklist: docs/BE-PR-001-rename-impact.md
- TASKLIST.md: BE-PR-001 marked complete
All 21 proposal tests pass.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.