Skip to content

feat(skills): add real-estate-assistant skill#62203

Open
Adonyth wants to merge 3 commits intoopenclaw:mainfrom
Adonyth:feat/real-estate-assistant-skill
Open

feat(skills): add real-estate-assistant skill#62203
Adonyth wants to merge 3 commits intoopenclaw:mainfrom
Adonyth:feat/real-estate-assistant-skill

Conversation

@Adonyth
Copy link
Copy Markdown

@Adonyth Adonyth commented Apr 7, 2026

Summary

  • Adds a real-estate-assistant skill purpose-built for real estate agents using OpenClaw
  • Lead pipeline management: track prospects through prospect → active → offer → closed/lost
  • Daily follow-up surfacing: never miss a client check-in
  • Property listing draft generator with professional/warm/luxury tone options
  • Weekly pipeline report with estimated deal value

Usage

# Add a lead
python scripts/realestate.py --add-lead --name "John Smith" --status prospect --budget 600000 --set-followup 2026-04-10

# Check today's follow-ups
python scripts/realestate.py --follow-ups

# Draft a listing
python scripts/realestate.py --draft-listing --address "123 Main St" --beds 3 --baths 2 --sqft 1800 --price 550000 --features "open plan, renovated kitchen" --tone luxury

# Pipeline report
python scripts/realestate.py --pipeline

Test plan

  • --add-lead creates lead with correct fields and UUID
  • --update-lead updates status, follow-up, and appends notes
  • --follow-ups shows leads due today or overdue, skips closed/lost
  • --pipeline groups by status and calculates active pipeline value
  • --draft-listing generates markdown with correct tone and saves to listings dir
  • --week filter works on pipeline

🤖 Generated with Claude Code

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 7, 2026

Greptile Summary

This PR adds two new skills: real-estate-assistant (lead pipeline management, follow-up surfacing, listing drafts, pipeline reports) and freelance-tracker (client time logging and invoice generation). Both are self-contained and functional, but both SKILL.md Quick Start sections contain the hardcoded personal path /Users/chenjiaxuan/openclaw/skills/… which must be replaced with a repo-relative path per the project docs policy ("no personal device names/hostnames/paths").

Confidence Score: 4/5

Not safe to merge as-is — both SKILL.md files expose a personal machine path that will produce broken instructions for every contributor who isn't the author.

The hardcoded personal path is a clear violation of the documented policy that docs content must use generic placeholders. All other findings are P2 or lower.

skills/real-estate-assistant/SKILL.md line 14 and skills/freelance-tracker/SKILL.md line 16 both need the absolute personal path replaced with a repo-relative path.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: skills/real-estate-assistant/SKILL.md
Line: 14

Comment:
**Hardcoded personal machine path in docs**

`/Users/chenjiaxuan/openclaw/skills/real-estate-assistant` is a personal filesystem path. Per the project docs policy, content must use generic placeholders — any other contributor will get a broken `cd` command. The same issue exists on line 16 of `skills/freelance-tracker/SKILL.md`.

```suggestion
   cd skills/real-estate-assistant
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: skills/real-estate-assistant/scripts/realestate.py
Line: 212

Comment:
**Unhandled `FileNotFoundError` if listing template is missing**

`TEMPLATE_PATH.read_text()` will raise an unhandled exception if the template is absent (e.g. partial clone, moved assets folder). A small guard gives a much friendlier error.

```suggestion
    if not TEMPLATE_PATH.exists():
        sys.exit(f"Listing template not found: {TEMPLATE_PATH}")
    template = TEMPLATE_PATH.read_text()
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(skills): add real-estate-assistant ..." | Re-trigger Greptile

## Quick Start
1. **Add a lead:**
```bash
cd /Users/chenjiaxuan/openclaw/skills/real-estate-assistant
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded personal machine path in docs

/Users/chenjiaxuan/openclaw/skills/real-estate-assistant is a personal filesystem path. Per the project docs policy, content must use generic placeholders — any other contributor will get a broken cd command. The same issue exists on line 16 of skills/freelance-tracker/SKILL.md.

Suggested change
cd /Users/chenjiaxuan/openclaw/skills/real-estate-assistant
cd skills/real-estate-assistant
Prompt To Fix With AI
This is a comment left during a code review.
Path: skills/real-estate-assistant/SKILL.md
Line: 14

Comment:
**Hardcoded personal machine path in docs**

`/Users/chenjiaxuan/openclaw/skills/real-estate-assistant` is a personal filesystem path. Per the project docs policy, content must use generic placeholders — any other contributor will get a broken `cd` command. The same issue exists on line 16 of `skills/freelance-tracker/SKILL.md`.

```suggestion
   cd skills/real-estate-assistant
```

How can I resolve this? If you propose a fix, please make it concise.

features = args.features or ""
highlights = "\n".join(f"- {f.strip().capitalize()}" for f in features.split(",") if f.strip())

template = TEMPLATE_PATH.read_text()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unhandled FileNotFoundError if listing template is missing

TEMPLATE_PATH.read_text() will raise an unhandled exception if the template is absent (e.g. partial clone, moved assets folder). A small guard gives a much friendlier error.

Suggested change
template = TEMPLATE_PATH.read_text()
if not TEMPLATE_PATH.exists():
sys.exit(f"Listing template not found: {TEMPLATE_PATH}")
template = TEMPLATE_PATH.read_text()
Prompt To Fix With AI
This is a comment left during a code review.
Path: skills/real-estate-assistant/scripts/realestate.py
Line: 212

Comment:
**Unhandled `FileNotFoundError` if listing template is missing**

`TEMPLATE_PATH.read_text()` will raise an unhandled exception if the template is absent (e.g. partial clone, moved assets folder). A small guard gives a much friendlier error.

```suggestion
    if not TEMPLATE_PATH.exists():
        sys.exit(f"Listing template not found: {TEMPLATE_PATH}")
    template = TEMPLATE_PATH.read_text()
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f6c6dd617

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

# Save invoice
out_dir = OUT_DIR / args.client
out_dir.mkdir(parents=True, exist_ok=True)
out_path = out_dir / f"invoice_{invoice_date}.md"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Save invoices with a unique filename per run

cmd_invoice computes an incrementing invoice_number, but the file is always written to invoice_{invoice_date}.md; generating a second invoice for the same client on the same day overwrites the first file while both batches are marked billed, which causes silent data loss in the exported invoice history.

Useful? React with 👍 / 👎.


def cmd_init_client(args: argparse.Namespace) -> None:
client = args.init_client
client_dir = CLIENTS_DIR / client
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate client slug before building filesystem paths

cmd_init_client uses the raw --init-client value directly in path joins, so values containing traversal segments (for example ../) escape the intended clients/ subtree and create/read files outside the skill’s managed directory structure, which is an arbitrary file-write risk if input is malformed or user-controlled.

Useful? React with 👍 / 👎.

date=date_str,
)

slug = args.address.lower().replace(" ", "-").replace(",", "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Sanitize listing slug to keep writes inside listings dir

The listing filename slug only strips spaces and commas from --address; path separators and .. survive, so out_path can resolve outside LISTINGS_DIR (for example via an address like ../../foo), allowing writes to unintended locations instead of the listings folder.

Useful? React with 👍 / 👎.

@Adonyth Adonyth force-pushed the feat/real-estate-assistant-skill branch from 0f6c6dd to 3cfa58c Compare April 7, 2026 18:31
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3cfa58cd2f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

# ---------------------------------------------------------------------------

def load_config(client: str) -> dict:
path = CLIENTS_DIR / client / "config.json"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate --client before joining filesystem paths

--client is used directly in path joins, so absolute paths or traversal values (for example /tmp/x or ../../x) escape the managed clients/ tree; commands like --log and --invoice then read/write config.json, log.json, and invoice files outside ~/openclaw-work/freelance, which is an arbitrary file access risk whenever the CLI input is malformed or user-controlled.

Useful? React with 👍 / 👎.

leads = load_leads()
today = dt.date.today().isoformat()
active = [l for l in leads if l["status"] not in ("closed", "lost")]
due = [l for l in active if l.get("next_followup") and l["next_followup"] <= today]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse follow-up dates before due-date comparisons

Follow-up dates are stored as free-form strings and later compared lexicographically (next_followup <= today), so non-normalized inputs like 2026-2-1 are treated as later than 2026-04-07 and never surface as overdue; this silently breaks the --follow-ups reminder workflow for users who provide valid calendar dates in non-zero-padded formats.

Useful? React with 👍 / 👎.

Comment on lines +72 to +73
if lead["id"] == lead_id or lead["id"].startswith(lead_id):
return lead
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject ambiguous lead ID prefixes during lookup

find_lead returns the first lead whose UUID starts with the supplied prefix, so --update-lead --id <short-prefix> can silently update the wrong record when multiple leads share that prefix; this causes data corruption in status/follow-up/notes updates instead of forcing the user to provide a unique or full ID.

Useful? React with 👍 / 👎.

@Adonyth
Copy link
Copy Markdown
Author

Adonyth commented Apr 7, 2026

CI failure is pre-existing — not introduced by this PR

The CI / check-additional failure (lint:extensions:bundled + lint:extensions:channels) shows 520 no-unnecessary-type-assertion errors all inside extensions/ — a directory this PR does not touch.

Verified locally: running the same lint on origin/main yields the same 520 errors:

Found 0 warnings and 520 errors.   ← origin/main
Found 0 warnings and 520 errors.   ← this PR branch

This PR only adds files under skills/real-estate-assistant/ and skills/freelance-tracker/ with zero modifications to extensions or tooling. The CI failure is a pre-existing issue in the repo and does not reflect on the quality of these changes.

Adonyth and others added 2 commits April 7, 2026 16:34
Adds a new skill for tracking freelance hours and generating markdown
invoices. Supports multiple clients, hourly rate config, time logging,
weekly/monthly summaries, and invoice generation with billed-entry
tracking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a skill for real estate agents running OpenClaw. Features:
- Lead management with status pipeline (prospect → active → offer → closed/lost)
- Daily follow-up surfacing so no client falls through the cracks
- Property listing draft generator with professional/warm/luxury tones
- Weekly pipeline report with estimated deal value

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Adonyth Adonyth force-pushed the feat/real-estate-assistant-skill branch from 3cfa58c to ca3d5f1 Compare April 7, 2026 20:34
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca3d5f146a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

)

slug = args.address.lower().replace(" ", "-").replace(",", "")
out_path = LISTINGS_DIR / f"{slug}_{date_str}.md"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve listing drafts with unique output filenames

Save paths are keyed only by normalized address and current date, so generating multiple drafts for the same property on the same day (for example after changing tone or features) silently overwrites the previous file and loses work; include a unique suffix (timestamp or sequence) in the filename to keep each draft.

Useful? React with 👍 / 👎.

project = rest.strip()
description = ""

entry_date = date or dt.date.today().isoformat()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce YYYY-MM-DD when accepting backfilled log dates

--date is documented as YYYY-MM-DD, but the value is stored verbatim without validation, which lets malformed dates (for example 2026-4-2 or 2026-99-01) enter log.json; later week/month filters rely on string comparisons, so these entries can be misclassified and produce inaccurate summaries/invoice timelines.

Useful? React with 👍 / 👎.

… and fetch-guard tests

Cast buildPendingPayload/buildResolvedResult return values to concrete
payload shapes in slack and telegram runtime tests to fix TS18046
'payload is of type unknown' errors.

Add curly braces around single-line if bodies in fetch-guard ssrf test
to satisfy the eslint curly rule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@openclaw-barnacle openclaw-barnacle bot added channel: slack Channel integration: slack channel: telegram Channel integration: telegram labels Apr 7, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 16d4e490d4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if args.week:
today = dt.date.today()
week_start = (today - dt.timedelta(days=today.weekday())).isoformat()
entries = [e for e in entries if e["date"] >= week_start]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict --week summaries to the current week window

The --week filter currently keeps entries where date >= week_start, which also includes future-dated logs (for example, a typo like 2026-05-01 when run on 2026-04-07). That inflates the “current week” totals and can mislead billing decisions based on this summary; the filter should bound dates to the intended week range (or at least <= today) after date parsing.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack channel: telegram Channel integration: telegram size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant