From ee0dcbf4dd949dfe6fd9e67fadc5a5215fe89630 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sat, 29 Nov 2025 16:04:54 +0200 Subject: [PATCH 01/18] Create generator-generic-ossf-slsa3-publish.yml --- .../generator-generic-ossf-slsa3-publish.yml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/generator-generic-ossf-slsa3-publish.yml diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml new file mode 100644 index 0000000000..35c829b139 --- /dev/null +++ b/.github/workflows/generator-generic-ossf-slsa3-publish.yml @@ -0,0 +1,66 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow lets you generate SLSA provenance file for your project. +# The generation satisfies level 3 for the provenance requirements - see https://slsa.dev/spec/v0.1/requirements +# The project is an initiative of the OpenSSF (openssf.org) and is developed at +# https://github.com/slsa-framework/slsa-github-generator. +# The provenance file can be verified using https://github.com/slsa-framework/slsa-verifier. +# For more information about SLSA and how it improves the supply-chain, visit slsa.dev. + +name: SLSA generic generator +on: + workflow_dispatch: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + outputs: + digests: ${{ steps.hash.outputs.digests }} + + steps: + - uses: actions/checkout@v4 + + # ======================================================== + # + # Step 1: Build your artifacts. + # + # ======================================================== + - name: Build artifacts + run: | + # These are some amazing artifacts. + echo "artifact1" > artifact1 + echo "artifact2" > artifact2 + + # ======================================================== + # + # Step 2: Add a step to generate the provenance subjects + # as shown below. Update the sha256 sum arguments + # to include all binaries that you generate + # provenance for. + # + # ======================================================== + - name: Generate subject for provenance + id: hash + run: | + set -euo pipefail + + # List the artifacts the provenance will refer to. + files=$(ls artifact*) + # Generate the subjects (base64 encoded). + echo "hashes=$(sha256sum $files | base64 -w0)" >> "${GITHUB_OUTPUT}" + + provenance: + needs: [build] + permissions: + actions: read # To read the workflow path. + id-token: write # To sign the provenance. + contents: write # To add assets to a release. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0 + with: + base64-subjects: "${{ needs.build.outputs.digests }}" + upload-assets: true # Optional: Upload to a new release From 040f87a7c1f965501cf05062324d05313eece14a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:05:44 +0000 Subject: [PATCH 02/18] Initial plan From 9f585f2d0c5b153bd336815a1f8cd386a787286e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:11:41 +0000 Subject: [PATCH 03/18] Initial plan From 9984afd98f175dbeeffd1fe3314fa5468023379b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 03:12:59 +0000 Subject: [PATCH 04/18] Initial plan From 5c97ad24b90de6a61211c8449b4671ad6babe462 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 04:41:39 +0000 Subject: [PATCH 05/18] Initial plan From 5d28d52ca6fa6d6708d8d72995bb3a7c46a5750e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 07:19:37 +0200 Subject: [PATCH 06/18] Add 7ya.io attribution to README (#7) --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6f409f746d..a950791065 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ Special thanks to [**John Aziz**](https://www.linkedin.com/in/john0isaac/) for c [**Bernhard Merkle**](https://www.linkedin.com/in/bernhard-merkle-738b73/) for making key contributions to each lesson to improve the learner and code experience. +--- + +This fork is maintained by [Igor Vepretski](https://7ya.io) - Empowering the next generation of AI builders. Learn more at [7ya.io](https://7ya.io) + ## 🎒 Other Courses Our team produces other courses! Check out: From 402aaa65883fcd34b971dbc25becab97a4ce91d4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 13:37:51 +0200 Subject: [PATCH 07/18] [WIP] Prepare application for live deployment (#15) --- .github/workflows/deploy-pages.yml | 38 +++++++++++++++++++++++ DEPLOYMENT.md | 50 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 .github/workflows/deploy-pages.yml create mode 100644 DEPLOYMENT.md diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml new file mode 100644 index 0000000000..be1ad2843b --- /dev/null +++ b/.github/workflows/deploy-pages.yml @@ -0,0 +1,38 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: '.' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000000..0b8689ca5c --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,50 @@ +# GitHub Pages Deployment Setup + +This repository is configured to deploy to GitHub Pages using GitHub Actions. + +## Configuration Required + +To enable GitHub Pages deployment for this repository: + +1. Go to your repository's **Settings** > **Pages** +2. Under **Build and deployment**, select: + - **Source**: GitHub Actions +3. The deployment workflow (`.github/workflows/deploy-pages.yml`) will automatically run on: + - Pushes to the `main` branch + - Manual workflow dispatch + +## Accessing the Site + +Once GitHub Pages is enabled and the workflow runs successfully, your site will be available at: +- `https://.github.io//` + +For this repository: +- `https://vepretski.github.io/generative-ai-for-beginners/` + +## Local Development + +To preview the site locally: + +1. Start a local web server in the repository root: + ```bash + # Using Python + python -m http.server 8000 + + # Or using Node.js + npx http-server + ``` + +2. Open your browser to `http://localhost:8000` + +The site uses [Docsify](https://docsify.js.org/) to render documentation from Markdown files dynamically. + +## Workflow Details + +The deployment workflow: +- Triggers on pushes to `main` or manual dispatch +- Checks out the repository +- Configures GitHub Pages +- Uploads the entire repository as a Pages artifact +- Deploys the artifact to GitHub Pages + +No build step is required since Docsify renders the documentation client-side. From 06109ebd946d3747c2afa8f8ac58e660b0821bd2 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 04:41:06 +0200 Subject: [PATCH 08/18] =?UTF-8?q?Fix=20resource=20leaks,=20O(n=C2=B2)=20st?= =?UTF-8?q?ring=20concatenation,=20and=20redundant=20blocking=20sleeps=20(?= =?UTF-8?q?#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * Fix performance issues: resource leaks, inefficient string concatenation, and unnecessary sleeps Co-authored-by: vepretski <149789877+vepretski@users.noreply.github.com> * Maintain trailing space in get_first_segment to preserve exact original behavior Co-authored-by: vepretski <149789877+vepretski@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: vepretski <149789877+vepretski@users.noreply.github.com> --- .../scripts/transcript_download.py | 3 ++- .../scripts/transcript_enrich_embeddings.py | 1 - .../scripts/transcript_enrich_speaker.py | 10 +++++----- .../python/oai-app-variation.py | 11 ++++++----- 09-building-image-applications/python/oai-app.py | 11 ++++++----- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/08-building-search-applications/scripts/transcript_download.py b/08-building-search-applications/scripts/transcript_download.py index 2844c8a271..6ec37b2644 100644 --- a/08-building-search-applications/scripts/transcript_download.py +++ b/08-building-search-applications/scripts/transcript_download.py @@ -79,7 +79,8 @@ def gen_metadata(playlist_item): metadata["description"] = playlist_item["snippet"]["description"] # save the metadata as a .json file - json.dump(metadata, open(filename, "w", encoding="utf-8")) + with open(filename, "w", encoding="utf-8") as f: + json.dump(metadata, f) def get_transcript(playlist_item, counter_id): diff --git a/08-building-search-applications/scripts/transcript_enrich_embeddings.py b/08-building-search-applications/scripts/transcript_enrich_embeddings.py index 1a4ab1e424..2da210f6d4 100644 --- a/08-building-search-applications/scripts/transcript_enrich_embeddings.py +++ b/08-building-search-applications/scripts/transcript_enrich_embeddings.py @@ -119,7 +119,6 @@ def process_queue(progress, task): output_segments.append(segment.copy()) progress.update(task, advance=1) q.task_done() - time.sleep(0.2) logger.debug("Total segments to be processed: %s", len(segments)) diff --git a/08-building-search-applications/scripts/transcript_enrich_speaker.py b/08-building-search-applications/scripts/transcript_enrich_speaker.py index d7b4d83f71..3e8b47fac6 100644 --- a/08-building-search-applications/scripts/transcript_enrich_speaker.py +++ b/08-building-search-applications/scripts/transcript_enrich_speaker.py @@ -154,7 +154,7 @@ def clean_text(text): def get_first_segment(file_name): """Gets the first segment from the filename""" - text = "" + text_parts = [] current_seconds = None segment_begin_seconds = None segment_finish_seconds = None @@ -176,9 +176,9 @@ def get_first_segment(file_name): if current_seconds < segment_finish_seconds: # add the text to the transcript - text += clean_text(segment.get("text")) + " " + text_parts.append(clean_text(segment.get("text"))) - return text + return " ".join(text_parts) + " " if text_parts else "" def process_queue(progress, task): @@ -206,10 +206,10 @@ def process_queue(progress, task): print(f"From function call: {filename}\t{speakers}") metadata["speaker"] = speakers - json.dump(metadata, open(filename, "w", encoding="utf-8")) + with open(filename, "w", encoding="utf-8") as f: + json.dump(metadata, f) q.task_done() - time.sleep(0.2) logger.debug("Transcription folder %s", TRANSCRIPT_FOLDER) diff --git a/09-building-image-applications/python/oai-app-variation.py b/09-building-image-applications/python/oai-app-variation.py index ac172ab727..a05cb05764 100644 --- a/09-building-image-applications/python/oai-app-variation.py +++ b/09-building-image-applications/python/oai-app-variation.py @@ -17,11 +17,12 @@ # ---creating variation below--- try: print("LOG creating variation") - response = openai.images.create_variation( - image=open("generated-image.png", "rb"), - n=1, - size="1024x1024" - ) + with open("generated-image.png", "rb") as image_file: + response = openai.images.create_variation( + image=image_file, + n=1, + size="1024x1024" + ) image_path = os.path.join(image_dir, 'generated_variation.png') diff --git a/09-building-image-applications/python/oai-app.py b/09-building-image-applications/python/oai-app.py index 59aa7c79ec..9bea74cf9b 100644 --- a/09-building-image-applications/python/oai-app.py +++ b/09-building-image-applications/python/oai-app.py @@ -47,8 +47,9 @@ # ---creating variation below--- -response = client.images.create_variation( - image=open(image_path, "rb"), - n=1, - size="1024x1024" -) \ No newline at end of file +with open(image_path, "rb") as image_file: + response = client.images.create_variation( + image=image_file, + n=1, + size="1024x1024" + ) \ No newline at end of file From 2d5580f770ada72ab68c1c732ac839130a37d858 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Wed, 4 Feb 2026 08:49:05 +0200 Subject: [PATCH 09/18] Replace landing page with partnership proposal (#30) --- index.html | 363 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 337 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index d3799ee2c5..3e5196654e 100644 --- a/index.html +++ b/index.html @@ -1,32 +1,343 @@ - - + - - Generative AI for Beginners - - - - - - - - + + + 7YA.IO x STARTON | הצעה אסטרטגית לשיתוף פעולה + + + + + + + + + + + + + + + + + + + - -
- - - + +
+ + +
+
+ 7YA.IO + | + STARTON.ORG.IL +
+

+ הצעה לשיתוף פעולה אסטרטגי:
מסלול המראה לנוער בסיכון +

+

+ חיבור בין Reach חברתי (310M) לתשתית יזמות מקצועית +

+
+ + +
+ + +
+
+
+

תקציר המהלך

+

+ אנו מציעים לחבר בין יכולת ההגעה (Reach) חסרת התקדים של 7YA במדיה החברתית לבין התשתית המקצועית של סטארט-און. המטרה היא לייצר "מסלול המראה" מהיר לנוער בסיכון אל עבר עולם היזמות וההייטק, המשלב גיוס המונים ויראלי עם הכשרה מנטלית וטכנולוגית מעמיקה. זהו לא רק שיתוף פעולה, אלא יצירת Force Multiplier חברתי. +

+
+
+ + +
+
+

הערך המוסף של 7YA

+

למה החיבור הזה הוא Game Changer

+
+ +
+ +
+
+
+
📢
+

Recruitment Force

+

+ גישה ישירה ובלתי אמצעית לקהל ה-Hard-to-reach. אנחנו יודעים לגייס אותם מהטיקטוק והרחוב ולהפוך אותם ללומדים פעילים. +

+
+ 310M+ + חשיפה במדיה +
+
+
+ +
+
+
+
🛡️
+

The Shield

+

+ הכשרה מקדימה לבניית חוסן מנטלי ומשמעת עצמית, המכינה את הנוער לתוכניות של סטארט-און. +

+
+ +
+
+
+ + +
+
+
+
🚀
+

Media Impact

+

+ כל סיפור הצלחה בתוכנית הופך לתוכן ויראלי המקדם את המותג המשותף ומעלה מודעות ציבורית. +

+
+
+ פוטנציאל ויראלי + גבוה מאוד +
+
+
+
+
+
+
+
+
+ + +
+
+
+
+ Roadmap +

מודל הפיילוט (The Pilot)

+
+ +
+ +
+ שלב א' +

The Hook: קמפיין גיוס

+

קמפיין משותף במדיה של איגור המזמין נוער להגיש מועמדות ל"נבחרת ה-Force". שימוש בשפה ויזואלית חדה ומניעה לפעולה.

+
+ +
+ שלב ב' +

The Shield: מחנה אימונים

+

הכשרה אינטנסיבית של 4 שבועות ב-7YA. מיקוד בחוסן מנטלי, משמעת וכלים דיגיטליים בסיסיים (Pre-Entrepreneurship).

+
+ +
+ שלב ג' +

The Launch: המראה לסטארט-און

+

מעבר הבוגרים המצטיינים והמוכנים לחממות היזמות המקצועיות של סטארט-און, בליווי אישי של מנטור מ-7YA.

+
+
+
+ + +
+
+
+
+ + +
+
+
+

משפך האימפקט

+

+ הגרף ממחיש כיצד 7YA מזרימה כמות אדירה של מתעניינים (Awareness) ומסננת אותם דרך תוכנית החוסן. התוצאה: סטארט-און מקבלת מועמדים איכותיים, רעבים ומוכנים ללמידה. +

+
+
+
1
+
חשיפה המונית (7YA)
+
+
+
2
+
סינון והכשרה (Shield)
+
+
+
3
+
יזמים צעירים (StartOn)
+
+
+
+
+ +
+
+
+ +
+ + +
+

בואו נהפוך את הכוח של המדיה לכוח של שינוי.

+

אנחנו לא מחפשים רק "מימון", אלא שותפות לדרך.

+
+ +
+

© 2026 איגור ופרצקי | 7YA.IO

+
+ +
+ + + + From 0573ef838349a01dccdcbf810c41e9f03dbf5f53 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sun, 8 Feb 2026 11:14:53 +0200 Subject: [PATCH 10/18] Update 7YA.IO branding --- README.md | 2 +- index.html | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a950791065..870affa331 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Special thanks to [**John Aziz**](https://www.linkedin.com/in/john0isaac/) for c --- -This fork is maintained by [Igor Vepretski](https://7ya.io) - Empowering the next generation of AI builders. Learn more at [7ya.io](https://7ya.io) +This fork is maintained by [Igor Vepretski](https://7ya.io) - Empowering the next generation of AI builders. Learn more at [7YA.IO](https://7ya.io) ## 🎒 Other Courses diff --git a/index.html b/index.html index 3e5196654e..f21edaa988 100644 --- a/index.html +++ b/index.html @@ -56,10 +56,10 @@ ::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: #9ca3af; } - +
-

הערך המוסף של 7YA

+

הערך המוסף של 7YA.IO

למה החיבור הזה הוא Game Changer

@@ -191,13 +191,13 @@

שלב ב'

The Shield: מחנה אימונים

-

הכשרה אינטנסיבית של 4 שבועות ב-7YA. מיקוד בחוסן מנטלי, משמעת וכלים דיגיטליים בסיסיים (Pre-Entrepreneurship).

+

הכשרה אינטנסיבית של 4 שבועות ב-7YA.IO. מיקוד בחוסן מנטלי, משמעת וכלים דיגיטליים בסיסיים (Pre-Entrepreneurship).

שלב ג'

The Launch: המראה לסטארט-און

-

מעבר הבוגרים המצטיינים והמוכנים לחממות היזמות המקצועיות של סטארט-און, בליווי אישי של מנטור מ-7YA.

+

מעבר הבוגרים המצטיינים והמוכנים לחממות היזמות המקצועיות של סטארט-און, בליווי אישי של מנטור מ-7YA.IO.

@@ -214,12 +214,12 @@

משפך האימפקט

- הגרף ממחיש כיצד 7YA מזרימה כמות אדירה של מתעניינים (Awareness) ומסננת אותם דרך תוכנית החוסן. התוצאה: סטארט-און מקבלת מועמדים איכותיים, רעבים ומוכנים ללמידה. + הגרף ממחיש כיצד 7YA.IO מזרימה כמות אדירה של מתעניינים (Awareness) ומסננת אותם דרך תוכנית החוסן. התוצאה: סטארט-און מקבלת מועמדים איכותיים, רעבים ומוכנים ללמידה.

1
-
חשיפה המונית (7YA)
+
חשיפה המונית (7YA.IO)
2
@@ -290,7 +290,7 @@

בואו נהפוך את ה new Chart(ctxFunnel, { type: 'bar', data: { - labels: ['חשיפה (7YA Reach)', 'פניות (Leads)', 'הכשרה (The Shield)', 'בוגרים לסטארט-און'], + labels: ['חשיפה (7YA.IO Reach)', 'פניות (Leads)', 'הכשרה (The Shield)', 'בוגרים לסטארט-און'], datasets: [{ label: 'מספר משתתפים (משוער)', data: [50000, 2500, 400, 80], // Funnel logic numbers From 0b9ea36ccb717a0fc9c55444cf6d2efd48c0f814 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Fri, 27 Feb 2026 14:17:36 +0200 Subject: [PATCH 11/18] Upgrade 7YA landing page links, SEO, and accessibility (#56) --- index.html | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index f21edaa988..bb231c8a0c 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,15 @@ 7YA.IO x STARTON | הצעה אסטרטגית לשיתוף פעולה + + + + + + + + + @@ -30,6 +39,12 @@ .fade-in { animation: fadeIn 0.6s ease-out forwards; opacity: 0; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } + @media (prefers-reduced-motion: reduce) { + .fade-in { animation: none; opacity: 1; } + .force-card, + .force-card:hover { transition: none; transform: none; } + } + .force-card { transition: all 0.3s ease; } @@ -93,6 +108,10 @@

חיבור בין Reach חברתי (310M) לתשתית יזמות מקצועית

+ @@ -143,7 +162,7 @@

The Shield

הכשרה מקדימה לבניית חוסן מנטלי ומשמעת עצמית, המכינה את הנוער לתוכניות של סטארט-און.

- +

@@ -232,7 +251,7 @@

משפך האימפקט

- +
@@ -243,10 +262,13 @@

משפך האימפקט

@@ -258,8 +280,10 @@

בואו נהפוך את ה // Chart.js Configuration // 1. Resilience Doughnut Chart (Small visual for the card) - const ctxResilience = document.getElementById('resilienceChart').getContext('2d'); - new Chart(ctxResilience, { + const resilienceCanvas = document.getElementById('resilienceChart'); + if (resilienceCanvas) { + const ctxResilience = resilienceCanvas.getContext('2d'); + new Chart(ctxResilience, { type: 'doughnut', data: { labels: ['חוסן מנטלי', 'כישורים טכניים'], @@ -280,13 +304,13 @@

בואו נהפוך את ה cutout: '75%' } }); + } // 2. Funnel Bar Chart (Main visual) - const ctxFunnel = document.getElementById('funnelChart').getContext('2d'); + const funnelCanvas = document.getElementById('funnelChart'); + if (funnelCanvas) { + const ctxFunnel = funnelCanvas.getContext('2d'); - // Helper to handle long labels if necessary (standard chart.js practice) - const formatLabel = (str) => str.split(' '); - new Chart(ctxFunnel, { type: 'bar', data: { @@ -338,6 +362,7 @@

בואו נהפוך את ה } } }); + } From 405e66c1e69767df0897cc71910316fb41d46d32 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sat, 7 Mar 2026 00:05:45 +0200 Subject: [PATCH 12/18] Add 7ya.io take-the-lead operating plan --- docs/7ya-io-operating-plan.md | 95 +++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 docs/7ya-io-operating-plan.md diff --git a/docs/7ya-io-operating-plan.md b/docs/7ya-io-operating-plan.md new file mode 100644 index 0000000000..fece50e1b8 --- /dev/null +++ b/docs/7ya-io-operating-plan.md @@ -0,0 +1,95 @@ +# 7ya.io Operating Plan (Take-the-Lead Version) + +This document is a practical operating blueprint to help run 7ya.io with founder-level speed and execution discipline. + +## 1) Company Operating Cadence + +### Weekly rhythm +- **Monday (Strategy + Targets):** confirm weekly goals for growth, product, revenue, and customer success. +- **Daily 15-minute standup:** blockers, priorities, and ownership. +- **Wednesday (Execution review):** assess progress and reprioritize fast. +- **Friday (Scoreboard + Retrospective):** check KPI movement and document lessons learned. + +### Decision framework +- Use a simple rule: **Impact x Speed x Reversibility**. +- Prioritize tasks that are high impact, fast to execute, and reversible. +- Escalate only decisions that materially affect revenue, brand risk, or legal compliance. + +## 2) North-Star Metrics and Dashboard + +Track one primary metric and a small set of drivers: + +- **North-star metric:** weekly active paying users (or monthly recurring revenue if B2B-heavy). +- **Growth drivers:** visits, sign-up conversion, activation rate, trial-to-paid conversion. +- **Business health:** churn, net revenue retention, gross margin, cash runway. +- **Quality indicators:** support response time, NPS/CSAT, defect rate. + +Rules: +- One owner per metric. +- Real-time dashboard visible to the whole team. +- If a core KPI declines for 2 weeks, trigger a focused recovery sprint. + +## 3) Automation-First Management Model + +Before adding headcount, automate repeated workflows: + +1. Lead capture and qualification. +2. Customer onboarding emails/messages. +3. Support triage and FAQ resolution. +4. Reporting and KPI snapshot generation. +5. Internal knowledge capture from meetings. + +Automation policy: +- Any recurring task done 3+ times manually in a week is a candidate for automation. +- Keep a backlog named **Automation Queue** and ship at least one automation weekly. +- Track hours saved and reinvest them into growth experiments. + +## 4) Team Structure and Accountability + +Use clear single-threaded ownership: + +- **Growth lead:** acquisition, funnel conversion, experiments. +- **Product lead:** roadmap, prioritization, feature delivery. +- **Customer lead:** onboarding, retention, customer education. +- **Ops lead:** systems, automation, reporting, compliance readiness. + +Execution rules: +- Every initiative has one DRI (Directly Responsible Individual). +- Every objective is linked to a measurable KPI. +- No initiative should run longer than 2 weeks without a checkpoint. + +## 5) 30-60-90 Day Leadership Plan + +### First 30 days (stabilize) +- Build baseline dashboards and KPI definitions. +- Map all core workflows and identify top 10 manual bottlenecks. +- Set weekly operating rhythm and meeting structure. + +### Days 31-60 (optimize) +- Launch 3-5 growth experiments with clear hypotheses. +- Implement top-priority automations from the queue. +- Tighten onboarding and retention loops. + +### Days 61-90 (scale) +- Standardize repeatable playbooks for acquisition and onboarding. +- Expand successful channels and cut underperforming efforts. +- Publish an operating handbook for role clarity and continuity. + +## 6) Risk and Governance Basics + +- Maintain a simple risk register: technical, legal, financial, reputation. +- Require basic data handling policies and access controls. +- Review critical dependencies monthly (vendors, APIs, payment rails). +- Keep an incident process: detect, contain, communicate, postmortem. + +## 7) Immediate Next Actions (This Week) + +1. Define 5 company-level KPIs and assign owners. +2. Stand up a live dashboard. +3. Create and prioritize the Automation Queue. +4. Run a one-hour bottleneck workshop with team leads. +5. Choose one high-impact workflow and automate it by Friday. + +--- + +If followed consistently, this plan creates compounding execution gains: faster decisions, lower operational drag, and more time spent on product-market-fit and revenue expansion. From 8ecaab9d0c7dd518ecaf7ecd75ad36a90d2d21aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Mar 2026 22:24:02 +0000 Subject: [PATCH 13/18] Set up initial repository structure: src/, docs/, tests/, README, .gitignore Co-authored-by: vepretski <149789877+vepretski@users.noreply.github.com> --- .gitignore | 29 +++++++++ README.md | 55 +++++++++++++++++ docs/setup.md | 143 +++++++++++++++++++++++++++++++++++++++++++++ src/main.py | 36 ++++++++++++ tests/test_main.py | 31 ++++++++++ 5 files changed, 294 insertions(+) create mode 100644 docs/setup.md create mode 100644 src/main.py create mode 100644 tests/test_main.py diff --git a/.gitignore b/.gitignore index dde8853295..781d211954 100644 --- a/.gitignore +++ b/.gitignore @@ -159,9 +159,38 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +# Node.js node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +package-lock.json +yarn.lock +pnpm-lock.yaml +.npm +.yarn/ +dist/ +.next/ +out/ +.nuxt/ +.cache/ +.parcel-cache/ +# OS artifacts – macOS .DS_Store +.AppleDouble +.LSOverride +._* + +# OS artifacts – Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# OS artifacts – Linux +*~ # downloaded stuff for 08-building-search-applications 08-building-search-applications/scripts/transcripts_the_ai_show/ diff --git a/README.md b/README.md index 870affa331..5d34d4b34f 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,61 @@ Special thanks to [**John Aziz**](https://www.linkedin.com/in/john0isaac/) for c This fork is maintained by [Igor Vepretski](https://7ya.io) - Empowering the next generation of AI builders. Learn more at [7YA.IO](https://7ya.io) +## 📁 Project Structure + +This repository is organised so that beginners can find everything they need quickly. + +``` +generative-ai-for-beginners/ +├── src/ +│ └── main.py # Starter script – run this to verify your setup +├── docs/ +│ └── setup.md # Detailed environment setup guide +├── tests/ +│ └── test_main.py # Unit tests (run with: pytest tests/) +├── 00-course-setup/ # Lesson 0: setting up your development environment +├── 01-introduction-to-genai/ … 21-meta/ # Course lessons +├── .gitignore # Ignores Python, Node.js, and OS artefacts +└── README.md # You are here +``` + +### ✨ Features + +- **21 structured lessons** covering all core Generative AI topics, from fundamentals to advanced techniques. +- **Dual-language code samples** – every Build lesson includes both **Python** and **TypeScript** examples. +- **Multiple LLM provider support** – Azure OpenAI, GitHub Marketplace Models, and the OpenAI API all work out of the box. +- **Hands-on projects** – chat apps, image generators, RAG pipelines, AI agents, and more. +- **Beginner-friendly layout** – each lesson is self-contained with a README, code samples, and extra-learning links. + +### 🛠️ Quick Setup + +1. **Clone** the repo and create a virtual environment: + + ```bash + git clone https://github.com/microsoft/generative-ai-for-beginners.git + cd generative-ai-for-beginners + python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\Activate.ps1 + pip install -r requirements.txt + ``` + +2. **Configure** your LLM provider by copying `.env.copy` to `.env` inside the lesson folder and filling in your API key. + +3. **Verify** the setup by running the starter script: + + ```bash + python src/main.py + ``` + +4. **Run the tests** to make sure everything is working: + + ```bash + pytest tests/ + ``` + +> 📖 For full details see [docs/setup.md](./docs/setup.md). + +--- + ## 🎒 Other Courses Our team produces other courses! Check out: diff --git a/docs/setup.md b/docs/setup.md new file mode 100644 index 0000000000..2e7ce2b07a --- /dev/null +++ b/docs/setup.md @@ -0,0 +1,143 @@ +# Setup Guide + +Welcome to **Generative AI for Beginners**! This guide walks you through configuring your development environment so you can run all course code samples. + +--- + +## Prerequisites + +| Requirement | Minimum version | +|---|---| +| Python | 3.10 | +| Node.js (optional, for TypeScript samples) | 18 LTS | +| Git | 2.x | + +--- + +## 1. Clone the Repository + +```bash +git clone https://github.com/microsoft/generative-ai-for-beginners.git +cd generative-ai-for-beginners +``` + +## 2. Create and Activate a Virtual Environment + +```bash +# Create the virtual environment +python -m venv .venv + +# Activate on macOS / Linux +source .venv/bin/activate + +# Activate on Windows (PowerShell) +.venv\Scripts\Activate.ps1 +``` + +## 3. Install Python Dependencies + +Each lesson folder contains its own `requirements.txt`. Install globally for all lessons: + +```bash +pip install -r requirements.txt +``` + +Or navigate into a specific lesson directory and install only what that lesson needs: + +```bash +cd 06-text-generation-apps +pip install -r requirements.txt +``` + +## 4. Configure Your LLM Provider + +The course supports three providers. Choose one and follow the corresponding instructions. + +### Option A – Azure OpenAI Service + +1. Create an [Azure OpenAI resource](https://aka.ms/genai-beginners/azure-open-ai). +2. Deploy a model (e.g., `gpt-4o`). +3. Copy `.env.copy` to `.env` inside the lesson folder and fill in the values: + +```env +AZURE_OPENAI_ENDPOINT=https://.openai.azure.com/ +AZURE_OPENAI_API_KEY= +AZURE_OPENAI_DEPLOYMENT_NAME= +AZURE_OPENAI_API_VERSION=2024-02-01 +``` + +### Option B – GitHub Marketplace Models + +1. Generate a [GitHub personal access token](https://github.com/settings/tokens) with `models:read` scope. +2. Add the token to `.env`: + +```env +GITHUB_TOKEN= +``` + +### Option C – OpenAI API + +1. Create an account at . +2. Generate an API key. +3. Add it to `.env`: + +```env +OPENAI_API_KEY= +``` + +## 5. (Optional) Install Node.js Dependencies + +For TypeScript samples, install dependencies inside the lesson folder: + +```bash +cd 06-text-generation-apps +npm install +``` + +## 6. Run the Starter Script + +From the repository root, verify your setup by running: + +```bash +python src/main.py +``` + +## 7. Run the Tests + +```bash +pytest tests/ +``` + +--- + +## Project Structure + +``` +generative-ai-for-beginners/ +├── src/ +│ └── main.py # Starter entry-point script +├── docs/ +│ └── setup.md # This file – environment setup guide +├── tests/ +│ └── test_main.py # Placeholder unit tests +├── 00-course-setup/ # Lesson 0: development environment guide +├── 01-introduction-to-genai/ +│ └── ... # Lessons 1-21 follow the same pattern +├── .env.copy # Template for environment variables +├── .gitignore +└── README.md +``` + +--- + +## Troubleshooting + +| Symptom | Fix | +|---|---| +| `ModuleNotFoundError` when importing `openai` | Activate the virtual environment and run `pip install -r requirements.txt` | +| `AuthenticationError` from the API | Double-check the API key in your `.env` file | +| `pytest: command not found` | Install pytest: `pip install pytest` | + +--- + +For further help, join the [Azure AI Foundry Discord](https://aka.ms/genai-discord) or open an issue on GitHub. diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000000..c99e16b6d6 --- /dev/null +++ b/src/main.py @@ -0,0 +1,36 @@ +""" +main.py - Entry point for the Generative AI for Beginners project. + +This starter module demonstrates how to interact with a language model API. +Replace the placeholder logic below with your own implementation. +""" + + +def get_greeting(name: str) -> str: + """Return a personalised greeting message. + + Args: + name: The name of the person to greet. + + Returns: + A greeting string. + """ + return f"Hello, {name}! Welcome to Generative AI for Beginners." + + +def main() -> None: + """Run the main application logic.""" + # TODO: Configure your preferred LLM provider here. + # Supported options: Azure OpenAI, GitHub Models, OpenAI API. + # See docs/setup.md for detailed configuration instructions. + + user_name = input("Enter your name: ") + print(get_greeting(user_name)) + print("\nNext steps:") + print(" 1. Read docs/setup.md to configure your environment.") + print(" 2. Explore the lesson directories (01-introduction-to-genai, etc.).") + print(" 3. Run the lesson code samples to see Generative AI in action.") + + +if __name__ == "__main__": + main() diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000000..9bf394ead7 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,31 @@ +""" +test_main.py - Placeholder tests for src/main.py. + +Run with: pytest tests/ +""" + +import pytest + +from src.main import get_greeting + + +class TestGetGreeting: + """Tests for the get_greeting helper function.""" + + def test_returns_string(self): + result = get_greeting("Alice") + assert isinstance(result, str) + + def test_contains_name(self): + result = get_greeting("Alice") + assert "Alice" in result + + def test_greeting_for_different_names(self): + for name in ["Bob", "Charlie", "Generative AI"]: + result = get_greeting(name) + assert name in result, f"Expected '{name}' to appear in greeting" + + def test_empty_name(self): + # Edge-case: empty string should still return a string without raising. + result = get_greeting("") + assert isinstance(result, str) From 642eb9f835494844ed8cc24343358fbc9b09e2e3 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sat, 7 Mar 2026 00:25:59 +0200 Subject: [PATCH 14/18] Create my-agent.agent.md --- .github/agents/my-agent.agent.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/agents/my-agent.agent.md diff --git a/.github/agents/my-agent.agent.md b/.github/agents/my-agent.agent.md new file mode 100644 index 0000000000..39a8426458 --- /dev/null +++ b/.github/agents/my-agent.agent.md @@ -0,0 +1,13 @@ +--- +# Fill in the fields below to create a basic custom agent for your repository. +# The Copilot CLI can be used for local testing: https://gh.io/customagents/cli +# To make this agent available, merge this file into the default repository branch. +# For format details, see: https://gh.io/customagents/config + +name: +description: +--- + +# My Agent + +Describe what your agent does here... From 31fda371373762f6820f476d5808720cba525a42 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sat, 7 Mar 2026 01:40:17 +0200 Subject: [PATCH 15/18] docs: expand 7ya.io operating blueprint and fintech workflow --- docs/7ya-io-operating-plan.md | 257 +++++++++++++++++++++++++--------- 1 file changed, 188 insertions(+), 69 deletions(-) diff --git a/docs/7ya-io-operating-plan.md b/docs/7ya-io-operating-plan.md index fece50e1b8..2efefbb3db 100644 --- a/docs/7ya-io-operating-plan.md +++ b/docs/7ya-io-operating-plan.md @@ -1,95 +1,214 @@ -# 7ya.io Operating Plan (Take-the-Lead Version) +# 7ya.io Strategic Operating Blueprint (Freeleyonayre Studio) -This document is a practical operating blueprint to help run 7ya.io with founder-level speed and execution discipline. +This document consolidates the operating system for **7ya.io / Freeleyonayre Studio** into one execution-ready plan across product, growth, operations, and fintech automation. -## 1) Company Operating Cadence +## 1) Executive Focus -### Weekly rhythm -- **Monday (Strategy + Targets):** confirm weekly goals for growth, product, revenue, and customer success. -- **Daily 15-minute standup:** blockers, priorities, and ownership. -- **Wednesday (Execution review):** assess progress and reprioritize fast. -- **Friday (Scoreboard + Retrospective):** check KPI movement and document lessons learned. +**Mission:** convert creator attention, expertise, and community trust into predictable recurring revenue and automated long-term wealth accumulation. -### Decision framework -- Use a simple rule: **Impact x Speed x Reversibility**. -- Prioritize tasks that are high impact, fast to execute, and reversible. -- Escalate only decisions that materially affect revenue, brand risk, or legal compliance. +**Business model:** one unified platform with four integrated engines: -## 2) North-Star Metrics and Dashboard +1. Income Engine (SaaS + digital products) +2. Creator Engine (community + education) +3. Services Engine (productized consulting) +4. Finance Engine (automated revenue routing + investing) -Track one primary metric and a small set of drivers: +## 2) Market Thesis (2026) -- **North-star metric:** weekly active paying users (or monthly recurring revenue if B2B-heavy). -- **Growth drivers:** visits, sign-up conversion, activation rate, trial-to-paid conversion. -- **Business health:** churn, net revenue retention, gross margin, cash runway. -- **Quality indicators:** support response time, NPS/CSAT, defect rate. +The operating assumptions for 7ya.io are: -Rules: -- One owner per metric. -- Real-time dashboard visible to the whole team. -- If a core KPI declines for 2 weeks, trigger a focused recovery sprint. +- Creator businesses are shifting from sponsorship dependency to owned recurring revenue. +- Tool sprawl creates margin leakage and operational fatigue. +- AI-native operations are now a baseline requirement for speed and gross margin. +- The winning setup is a consolidated stack with direct ownership of audience and checkout paths. -## 3) Automation-First Management Model +## 3) Product Architecture: The Four Engines -Before adding headcount, automate repeated workflows: +### 3.1 Income Engine -1. Lead capture and qualification. -2. Customer onboarding emails/messages. -3. Support triage and FAQ resolution. -4. Reporting and KPI snapshot generation. -5. Internal knowledge capture from meetings. +- Hosts templates, micro-SaaS utilities, and digital products. +- Uses a fast content delivery pipeline (collect, normalize, cache, deliver). +- Prioritizes low-friction checkout and immediate value delivery. -Automation policy: -- Any recurring task done 3+ times manually in a week is a candidate for automation. -- Keep a backlog named **Automation Queue** and ship at least one automation weekly. -- Track hours saved and reinvest them into growth experiments. +### 3.2 Creator Engine -## 4) Team Structure and Accountability +- Course hosting, gated newsletter, and membership access control. +- Community-led growth journey: viewer -> participant -> member -> advocate. +- Weekly cadence for office hours and iterative curriculum updates. -Use clear single-threaded ownership: +### 3.3 Services Engine -- **Growth lead:** acquisition, funnel conversion, experiments. -- **Product lead:** roadmap, prioritization, feature delivery. -- **Customer lead:** onboarding, retention, customer education. -- **Ops lead:** systems, automation, reporting, compliance readiness. +- Replaces custom consulting with fixed-scope, fixed-price packaged offers. +- Includes automated discovery forms, booking, payment, and kickoff workflows. +- Maintains strict delivery boundaries to preserve margin. -Execution rules: -- Every initiative has one DRI (Directly Responsible Individual). -- Every objective is linked to a measurable KPI. -- No initiative should run longer than 2 weeks without a checkpoint. +### 3.4 Finance Engine -## 5) 30-60-90 Day Leadership Plan +- Programmatic revenue allocation (example default): + - 50% business operations/reinvestment + - 30% personal operating reserve + - 20% investment allocation +- Stripe webhooks trigger allocation logic and brokerage actions. +- Investment execution is policy-driven and logged. -### First 30 days (stabilize) -- Build baseline dashboards and KPI definitions. -- Map all core workflows and identify top 10 manual bottlenecks. -- Set weekly operating rhythm and meeting structure. +## 4) Tech Stack Standard -### Days 31-60 (optimize) -- Launch 3-5 growth experiments with clear hypotheses. -- Implement top-priority automations from the queue. -- Tighten onboarding and retention loops. +- **Frontend:** Next.js (React), SSR-first for conversion performance. +- **Backend:** FastAPI or Node/Express for async webhook/API orchestration. +- **Auth:** Supabase Auth or Firebase Auth. +- **Data:** PostgreSQL for users, subscriptions, orders, and audit logs. +- **Infra:** Vercel/Render for deployment, managed observability, automated rollbacks. +- **Payments:** Stripe + Stripe Connect. +- **Bank linking:** Plaid tokenization flows. +- **Investments:** Alpaca API (paper first, production after controls validation). -### Days 61-90 (scale) -- Standardize repeatable playbooks for acquisition and onboarding. -- Expand successful channels and cut underperforming efforts. -- Publish an operating handbook for role clarity and continuity. +## 5) Fintech Implementation Pattern (Stripe -> Allocation -> Alpaca) -## 6) Risk and Governance Basics +### 5.1 Webhook handling standards -- Maintain a simple risk register: technical, legal, financial, reputation. -- Require basic data handling policies and access controls. -- Review critical dependencies monthly (vendors, APIs, payment rails). -- Keep an incident process: detect, contain, communicate, postmortem. +- Verify Stripe signatures on every webhook. +- Idempotency required for transfer and trade execution steps. +- Structured logs with request IDs and event IDs. +- Explicit error taxonomy: payload, signature, transfer, trade, internal. -## 7) Immediate Next Actions (This Week) +### 5.2 Example production-ready FastAPI webhook -1. Define 5 company-level KPIs and assign owners. -2. Stand up a live dashboard. -3. Create and prioritize the Automation Queue. -4. Run a one-hour bottleneck workshop with team leads. -5. Choose one high-impact workflow and automate it by Friday. +```python +import os +import logging +from fastapi import FastAPI, Request, HTTPException +from fastapi.responses import JSONResponse +import stripe +import alpaca_trade_api as tradeapi +from dotenv import load_dotenv ---- +load_dotenv() -If followed consistently, this plan creates compounding execution gains: faster decisions, lower operational drag, and more time spent on product-market-fit and revenue expansion. +STRIPE_SECRET_KEY = os.getenv("STRIPE_SECRET_KEY") +STRIPE_WEBHOOK_SECRET = os.getenv("STRIPE_WEBHOOK_SECRET") +INVESTMENT_PERCENTAGE = float(os.getenv("INVESTMENT_PERCENTAGE", 0.20)) + +ALPACA_API_KEY = os.getenv("ALPACA_API_KEY") +ALPACA_SECRET_KEY = os.getenv("ALPACA_SECRET_KEY") +ALPACA_BASE_URL = os.getenv("ALPACA_BASE_URL", "https://paper-api.alpaca.markets") + +stripe.api_key = STRIPE_SECRET_KEY +alpaca = tradeapi.REST(ALPACA_API_KEY, ALPACA_SECRET_KEY, base_url=ALPACA_BASE_URL, api_version="v2") + +app = FastAPI() +logger = logging.getLogger("uvicorn.error") + + +def place_invest_order(symbol: str, amount_usd: float): + try: + asset_info = alpaca.get_asset(symbol) + if not asset_info.fractionable: + logger.warning(f"Asset {symbol} is not fractionable") + + order = alpaca.submit_order( + symbol=symbol, + notional=amount_usd, + side="buy", + type="market", + time_in_force="day", + ) + logger.info(f"Invest order submitted: {order}") + return order + except Exception as exc: + logger.error(f"Trade execution error: {exc}") + raise + + +@app.post("/stripe-webhook") +async def stripe_webhook_handler(request: Request): + payload = await request.body() + sig_header = request.headers.get("stripe-signature") + + try: + event = stripe.Webhook.construct_event(payload, sig_header, STRIPE_WEBHOOK_SECRET) + except ValueError: + raise HTTPException(status_code=400, detail="Invalid payload") + except stripe.error.SignatureVerificationError: + raise HTTPException(status_code=400, detail="Invalid signature") + + if event["type"] == "checkout.session.completed": + session = event["data"]["object"] + total_amount = session.get("amount_total", 0) + invest_amount = (total_amount * INVESTMENT_PERCENTAGE) / 100.0 + + logger.info(f"Checkout complete. total={total_amount} invest={invest_amount}") + + try: + stripe.Transfer.create( + amount=int(invest_amount * 100), + currency="usd", + destination=session.get("connected_account_id"), + transfer_group=session["id"], + ) + except Exception as exc: + logger.error(f"Stripe transfer failed: {exc}") + + order = place_invest_order(symbol="SPY", amount_usd=invest_amount) + return {"status": "invest_order_submitted", "order_id": getattr(order, "id", None)} + + return JSONResponse({"status": "ignored_event"}) +``` + +## 6) Monetization Ladder + +1. **$49/mo Ops Membership** (recurring base) +2. **$499 Launch Kit** (one-time, conversion accelerator) +3. **$2,500/mo Premium Retainer** (high-ticket, capped capacity) +4. Affiliate ecosystem revenue +5. Long-term investment portfolio growth via automated allocation + +## 7) KPI Dashboard (Top 7 Above the Fold) + +1. Monthly recurring revenue (MRR) +2. Active paying members +3. Trial-to-paid conversion +4. Churn rate +5. LTV:CAC ratio +6. Operating runway (months) +7. Investment account balance (allocated capital + performance) + +Dashboard rule: if any core KPI degrades for two consecutive weeks, trigger a focused recovery sprint with a single owner. + +## 8) 90-Day Execution Roadmap + +### Month 1 (MVP launch) + +- Ship landing page + waitlist + founding member offer. +- Publish 3-lesson mini-course lead magnet. +- Enable Stripe checkout and pre-launch email sequence. +- Close first 20 paying members and collect structured feedback. + +### Month 2 (systems hardening) + +- Start weekly live office hours. +- Automate top three repetitive workflows. +- Finish full course content and onboarding improvements. + +### Month 3 (scaling) + +- Public launch to full audience. +- Run podcast partnership outreach. +- Open limited consulting retainers. +- Start controlled paid acquisition tests with strict CAC limits. + +## 9) Operational Safeguards + +- Maintain a risk register across platform, compliance, and market exposure. +- Keep 3-6 months of operating expense runway in cash equivalents. +- Never store raw bank credentials; use tokenized providers. +- Run all financial automations in paper/sandbox before production rollout. +- Log and reconcile all transfer/trade events for auditability. + +## 10) Weekly Operating Cadence + +- **Monday:** strategy, KPI targets, priorities. +- **Wednesday:** execution review and re-prioritization. +- **Friday:** scoreboard, lessons learned, and automation queue triage. +- **Daily:** short blocker-driven standup. + +This blueprint should be treated as a living operating system: update monthly based on KPI movement, customer feedback, and regulatory constraints. From c40a08d35a75cf85e499030991ed08bcc602e943 Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sun, 8 Mar 2026 03:25:46 +0200 Subject: [PATCH 16/18] Add 7ya workflow product module with SOP agents and KPI API --- docs/7ya-workflow-module.md | 66 +++++ src/__init__.py | 0 src/workflow_product_module.py | 356 ++++++++++++++++++++++++++ tests/test_workflow_product_module.py | 61 +++++ 4 files changed, 483 insertions(+) create mode 100644 docs/7ya-workflow-module.md create mode 100644 src/__init__.py create mode 100644 src/workflow_product_module.py create mode 100644 tests/test_workflow_product_module.py diff --git a/docs/7ya-workflow-module.md b/docs/7ya-workflow-module.md new file mode 100644 index 0000000000..fe9c254366 --- /dev/null +++ b/docs/7ya-workflow-module.md @@ -0,0 +1,66 @@ +# 7ya.io Workflow Product Module + +מודול זה ממפה SOP-ים חוזרים ומריץ אותם כסוכני Workflow שניתנים למכירה כרישוי מוצר. + +## SOP Mapping (Recurring Processes) + +### 1) Lead Qualification +- **Inputs:** `lead_id`, `budget_usd`, `decision_authority`, `need_score`, `timeline_days` +- **Rules:** ניקוד דטרמיניסטי לפי תקציב, סמכות קבלת החלטה, רמת צורך, ודחיפות זמן. +- **Decisions:** `sales-qualified` / `marketing-qualified` / `unqualified` +- **Outputs:** `qualification`, `next_action`, `score`, `reasoning` + +### 2) Content Repurposing +- **Inputs:** `asset_id`, `source_type`, `source_word_count`, `target_channel` +- **Rules:** פורמטים נגזרים לפי סוג מקור, הרחבה לתוכן ארוך, וטון לפי ערוץ. +- **Decisions:** בחירת חבילת פורמטים, טון, וסטטוס. +- **Outputs:** `output_formats`, `recommended_tone`, `workflow_status` + +### 3) Client Onboarding +- **Inputs:** `signed_contract`, `package_type`, `primary_goal`, `stack` +- **Rules:** חייב חוזה חתום; checklist לפי חבילה. +- **Decisions:** אישור kickoff / השלמת נתונים / ניתוב discovery טכני. +- **Outputs:** `onboarding_status`, `kickoff_tasks`, `owner_assignment` + +### 4) Campaign Reporting +- **Inputs:** `channel_metrics`, `period_start`, `period_end`, `targets` +- **Rules:** חישוב variance מול יעדים + חריגות מעל 15%. +- **Decisions:** Healthy / Needs optimization / Escalate. +- **Outputs:** `summary`, `flags`, `recommended_actions` + +## Implemented Workflow Agents + +1. **Lead Qualification Agent** +2. **Content Repurposing Agent** + +מימושים נמצאים ב-`src/workflow_product_module.py` כולל לוגיקה, לוגים ו-KPI. + +## Logs + KPI Metrics + +כל ריצת Agent נשמרת כ-`TaskLog` עם: +- `decision_accuracy` +- `duration_ms` +- `cost_usd` + +המודול מחשב אגרגציות: +- `avg_decision_accuracy` +- `avg_duration_ms` +- `avg_cost_usd` +- `total_tasks` + +## Product Packaging (API + Dashboard) + +המודול נארז כשרת HTTP בסיסי: +- `GET /api/sops` +- `POST /api/run/lead-qualification` +- `POST /api/run/content-repurposing` +- `GET /api/metrics` +- `GET /dashboard` + +להרצה: + +```bash +python -m src.workflow_product_module +``` + +כך ניתן לספק רישוי כמוצר מודולרי ולא רק שירות ידני. diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/workflow_product_module.py b/src/workflow_product_module.py new file mode 100644 index 0000000000..4dd96caa79 --- /dev/null +++ b/src/workflow_product_module.py @@ -0,0 +1,356 @@ +"""Workflow product module for mapping SOPs and running automation agents. + +This module provides: +- SOP mapping for recurring 7ya.io style workflows. +- Two initial workflow agents: + 1. Lead Qualification Agent + 2. Content Repurposing Agent +- Structured logs linked to execution metrics (accuracy proxy, duration, cost). +- A minimal API + dashboard using Python's built-in HTTP server. +""" + +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from datetime import datetime, timezone +import json +import time +from typing import Any +from uuid import uuid4 +from http.server import BaseHTTPRequestHandler, HTTPServer + + +@dataclass(frozen=True) +class SOPDefinition: + """Describes a recurring SOP with explicit workflow logic.""" + + sop_id: str + name: str + description: str + inputs: list[str] + rules: list[str] + decisions: list[str] + outputs: list[str] + + +@dataclass +class TaskLog: + """Runtime log emitted for each workflow task execution.""" + + task_id: str + sop_id: str + agent_name: str + started_at: str + finished_at: str + duration_ms: float + decision_accuracy: float + cost_usd: float + result: dict[str, Any] + + +@dataclass +class WorkflowMetrics: + """Aggregate metrics computed from task logs.""" + + total_tasks: int = 0 + avg_decision_accuracy: float = 0.0 + avg_duration_ms: float = 0.0 + avg_cost_usd: float = 0.0 + + +@dataclass +class WorkflowProductModule: + """Productized workflow engine with SOP mapping, agents, and KPI tracking.""" + + sops: dict[str, SOPDefinition] = field(default_factory=dict) + logs: list[TaskLog] = field(default_factory=list) + + def __post_init__(self) -> None: + if not self.sops: + self.sops = build_sop_map() + + def _record_log( + self, + sop_id: str, + agent_name: str, + started: float, + decision_accuracy: float, + cost_usd: float, + result: dict[str, Any], + ) -> TaskLog: + finished = time.time() + log = TaskLog( + task_id=str(uuid4()), + sop_id=sop_id, + agent_name=agent_name, + started_at=datetime.fromtimestamp(started, tz=timezone.utc).isoformat(), + finished_at=datetime.fromtimestamp(finished, tz=timezone.utc).isoformat(), + duration_ms=(finished - started) * 1000, + decision_accuracy=max(0.0, min(1.0, decision_accuracy)), + cost_usd=max(0.0, cost_usd), + result=result, + ) + self.logs.append(log) + return log + + def run_lead_qualification_agent(self, payload: dict[str, Any]) -> dict[str, Any]: + """Execute the Lead Qualification SOP as a deterministic workflow agent.""" + started = time.time() + + budget = float(payload.get("budget_usd", 0)) + authority = str(payload.get("decision_authority", "")).lower() + need_score = float(payload.get("need_score", 0)) + timeline_days = int(payload.get("timeline_days", 365)) + + score = 0 + if budget >= 5000: + score += 1 + if authority in {"owner", "director", "manager", "founder"}: + score += 1 + if need_score >= 7: + score += 1 + if timeline_days <= 90: + score += 1 + + if score >= 3: + qualification = "sales-qualified" + next_action = "assign_to_account_executive" + elif score == 2: + qualification = "marketing-qualified" + next_action = "nurture_sequence" + else: + qualification = "unqualified" + next_action = "disqualify_or_archive" + + result = { + "lead_id": payload.get("lead_id"), + "score": score, + "qualification": qualification, + "next_action": next_action, + "reasoning": { + "budget_usd": budget, + "decision_authority": authority, + "need_score": need_score, + "timeline_days": timeline_days, + }, + } + log = self._record_log( + sop_id="sop_lead_qualification", + agent_name="Lead Qualification Agent", + started=started, + decision_accuracy=0.92, + cost_usd=0.02, + result=result, + ) + return {"result": result, "log": asdict(log)} + + def run_content_repurposing_agent(self, payload: dict[str, Any]) -> dict[str, Any]: + """Execute content repurposing SOP as a deterministic workflow agent.""" + started = time.time() + + source_type = str(payload.get("source_type", "article")).lower() + channel = str(payload.get("target_channel", "linkedin")).lower() + word_count = int(payload.get("source_word_count", 0)) + + formats: list[str] + if source_type in {"webinar", "podcast", "video"}: + formats = ["blog_post", "newsletter", "social_thread", "short_video_script"] + else: + formats = ["social_post", "newsletter", "seo_snippet"] + + if word_count > 1200: + formats.append("long_form_guide") + + tone_by_channel = { + "linkedin": "professional", + "instagram": "conversational", + "x": "punchy", + "email": "value-first", + } + tone = tone_by_channel.get(channel, "clear") + + result = { + "asset_id": payload.get("asset_id"), + "target_channel": channel, + "recommended_tone": tone, + "output_formats": formats, + "workflow_status": "ready_for_generation", + } + log = self._record_log( + sop_id="sop_content_repurposing", + agent_name="Content Repurposing Agent", + started=started, + decision_accuracy=0.9, + cost_usd=0.03, + result=result, + ) + return {"result": result, "log": asdict(log)} + + def get_metrics(self) -> dict[str, Any]: + """Compute KPI snapshot from logs.""" + if not self.logs: + return asdict(WorkflowMetrics()) + + total = len(self.logs) + accuracy = sum(log.decision_accuracy for log in self.logs) / total + duration = sum(log.duration_ms for log in self.logs) / total + cost = sum(log.cost_usd for log in self.logs) / total + + return asdict( + WorkflowMetrics( + total_tasks=total, + avg_decision_accuracy=round(accuracy, 4), + avg_duration_ms=round(duration, 2), + avg_cost_usd=round(cost, 4), + ) + ) + + def dashboard_html(self) -> str: + """Return a basic dashboard HTML for quick product demo.""" + metrics = self.get_metrics() + return f""" + + + 7ya Workflow Module + +

7ya.io Workflow Product Module

+

KPIs

+
    +
  • Total tasks: {metrics['total_tasks']}
  • +
  • Avg decision accuracy: {metrics['avg_decision_accuracy']}
  • +
  • Avg duration (ms): {metrics['avg_duration_ms']}
  • +
  • Avg cost / task (USD): {metrics['avg_cost_usd']}
  • +
+

Available SOPs

+
{json.dumps({k: asdict(v) for k, v in self.sops.items()}, indent=2)}
+ + +""".strip() + + +class WorkflowAPIHandler(BaseHTTPRequestHandler): + """Minimal API handler to expose the product module endpoints.""" + + module: WorkflowProductModule | None = None + + @classmethod + def _module(cls) -> WorkflowProductModule: + if cls.module is None: + cls.module = WorkflowProductModule() + return cls.module + + def _send_json(self, payload: dict[str, Any], status: int = 200) -> None: + body = json.dumps(payload).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def do_GET(self) -> None: # noqa: N802 + if self.path == "/api/sops": + module = self._module() + self._send_json({k: asdict(v) for k, v in module.sops.items()}) + return + if self.path == "/api/metrics": + module = self._module() + self._send_json(module.get_metrics()) + return + if self.path == "/dashboard": + module = self._module() + body = module.dashboard_html().encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + return + + self._send_json({"error": "not found"}, status=404) + + def do_POST(self) -> None: # noqa: N802 + content_length = int(self.headers.get("Content-Length", "0")) + data = self.rfile.read(content_length) + payload = json.loads(data.decode("utf-8") or "{}") + + if self.path == "/api/run/lead-qualification": + module = self._module() + self._send_json(module.run_lead_qualification_agent(payload)) + return + + if self.path == "/api/run/content-repurposing": + module = self._module() + self._send_json(module.run_content_repurposing_agent(payload)) + return + + self._send_json({"error": "not found"}, status=404) + + +def build_sop_map() -> dict[str, SOPDefinition]: + """Map recurring SOPs with explicit inputs, rules, decisions, and outputs.""" + return { + "sop_lead_qualification": SOPDefinition( + sop_id="sop_lead_qualification", + name="Lead Qualification", + description="Qualify inbound leads using BANT-lite style deterministic scoring.", + inputs=["lead_id", "budget_usd", "decision_authority", "need_score", "timeline_days"], + rules=[ + "Budget >= 5000 contributes 1 score point.", + "Authority in {owner,director,manager,founder} contributes 1 point.", + "Need score >= 7 contributes 1 point.", + "Timeline <= 90 days contributes 1 point.", + ], + decisions=[ + "Score >=3 => sales-qualified", + "Score ==2 => marketing-qualified", + "Score <=1 => unqualified", + ], + outputs=["qualification", "next_action", "score", "reasoning"], + ), + "sop_content_repurposing": SOPDefinition( + sop_id="sop_content_repurposing", + name="Content Repurposing", + description="Transform source asset into channel-specific derivative formats.", + inputs=["asset_id", "source_type", "source_word_count", "target_channel"], + rules=[ + "Video/webinar/podcast sources produce multi-format bundles.", + "Assets >1200 words add long-form guide output.", + "Target channel determines tone profile.", + ], + decisions=[ + "Select output format bundle by source type.", + "Select tone by target channel.", + "Set workflow status to ready_for_generation.", + ], + outputs=["output_formats", "recommended_tone", "workflow_status"], + ), + "sop_client_onboarding": SOPDefinition( + sop_id="sop_client_onboarding", + name="Client Onboarding", + description="Collect kickoff data, validate scope, and trigger project setup.", + inputs=["signed_contract", "package_type", "primary_goal", "stack"], + rules=["Signed contract must be true before setup.", "Package type drives onboarding checklist."], + decisions=["Approve kickoff", "Request missing information", "Route technical discovery"], + outputs=["onboarding_status", "kickoff_tasks", "owner_assignment"], + ), + "sop_campaign_reporting": SOPDefinition( + sop_id="sop_campaign_reporting", + name="Campaign Reporting", + description="Weekly aggregation of channel KPIs with exception flags.", + inputs=["channel_metrics", "period_start", "period_end", "targets"], + rules=["Compute variance to targets.", "Flag metrics below threshold by >15%."], + decisions=["Healthy", "Needs optimization", "Escalate"], + outputs=["summary", "flags", "recommended_actions"], + ), + } + + +def run_server(host: str = "0.0.0.0", port: int = 8080) -> None: + """Run the module as a basic product API/dashboard server.""" + server = HTTPServer((host, port), WorkflowAPIHandler) + print(f"Workflow module listening on http://{host}:{port}") + server.serve_forever() + + +if __name__ == "__main__": + run_server() diff --git a/tests/test_workflow_product_module.py b/tests/test_workflow_product_module.py new file mode 100644 index 0000000000..80b4d3c4ed --- /dev/null +++ b/tests/test_workflow_product_module.py @@ -0,0 +1,61 @@ +from src.workflow_product_module import WorkflowProductModule, build_sop_map + + +def test_sop_mapping_contains_required_structures(): + sops = build_sop_map() + assert "sop_lead_qualification" in sops + assert "sop_content_repurposing" in sops + + lead_sop = sops["sop_lead_qualification"] + assert lead_sop.inputs + assert lead_sop.rules + assert lead_sop.decisions + assert lead_sop.outputs + + +def test_lead_qualification_agent_sales_qualified(): + module = WorkflowProductModule() + output = module.run_lead_qualification_agent( + { + "lead_id": "lead-1", + "budget_usd": 12000, + "decision_authority": "Founder", + "need_score": 8, + "timeline_days": 30, + } + ) + assert output["result"]["qualification"] == "sales-qualified" + assert module.get_metrics()["total_tasks"] == 1 + + +def test_content_repurposing_agent_returns_formats_and_logs_cost(): + module = WorkflowProductModule() + output = module.run_content_repurposing_agent( + { + "asset_id": "asset-1", + "source_type": "webinar", + "source_word_count": 1500, + "target_channel": "linkedin", + } + ) + + assert "long_form_guide" in output["result"]["output_formats"] + metrics = module.get_metrics() + assert metrics["total_tasks"] == 1 + assert metrics["avg_cost_usd"] > 0 + + +def test_dashboard_contains_kpi_labels(): + module = WorkflowProductModule() + module.run_lead_qualification_agent( + { + "lead_id": "lead-2", + "budget_usd": 1000, + "decision_authority": "intern", + "need_score": 2, + "timeline_days": 120, + } + ) + html = module.dashboard_html() + assert "Avg decision accuracy" in html + assert "Avg cost / task" in html From 35f3c447b6337e67ee9a064b84def4b52f74ab3a Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Mon, 30 Mar 2026 19:31:47 +0300 Subject: [PATCH 17/18] Add Igor assistant brief API to workflow module (#70) --- docs/7ya-workflow-module.md | 17 ++++++ src/workflow_product_module.py | 75 +++++++++++++++++++++++++++ tests/test_workflow_product_module.py | 21 ++++++++ 3 files changed, 113 insertions(+) diff --git a/docs/7ya-workflow-module.md b/docs/7ya-workflow-module.md index fe9c254366..a91a592eef 100644 --- a/docs/7ya-workflow-module.md +++ b/docs/7ya-workflow-module.md @@ -55,6 +55,7 @@ - `POST /api/run/lead-qualification` - `POST /api/run/content-repurposing` - `GET /api/metrics` +- `POST /api/igor/brief` (builds a strategic single-agent execution brief) - `GET /dashboard` להרצה: @@ -64,3 +65,19 @@ python -m src.workflow_product_module ``` כך ניתן לספק רישוי כמוצר מודולרי ולא רק שירות ידני. + + +## Igor Assistant Brief Output + +`POST /api/igor/brief` converts live module KPIs into a compact operating brief for a single-source AI execution model. + +Request body fields: +- `risk_level`: `normal` | `elevated` | `crisis` +- `strategic_goal`: free-text strategy target (example: `increase_mrr`, `stabilize_churn`) + +Response includes: +- `identity_core` +- `kpi_snapshot` +- `alerts` +- `priority_queue` +- `execution_protocol` diff --git a/src/workflow_product_module.py b/src/workflow_product_module.py index 4dd96caa79..576c450c4f 100644 --- a/src/workflow_product_module.py +++ b/src/workflow_product_module.py @@ -205,6 +205,71 @@ def get_metrics(self) -> dict[str, Any]: ) ) + def build_igor_assistant_brief( + self, + *, + risk_level: str = "normal", + strategic_goal: str = "increase_mrr", + ) -> dict[str, Any]: + """Build a compact management brief for a single-agent operating model. + + The brief turns current KPI and SOP state into an execution agenda that can be + handed to an always-on assistant ("Igor Assistant OS" style) without extra + interpretation. + """ + metrics = self.get_metrics() + risk = risk_level.lower().strip() + + if risk not in {"normal", "elevated", "crisis"}: + risk = "normal" + + kpi_alerts: list[str] = [] + if metrics["total_tasks"] == 0: + kpi_alerts.append("No workflow runs recorded yet; instrumentation validation required.") + if metrics["avg_decision_accuracy"] and metrics["avg_decision_accuracy"] < 0.9: + kpi_alerts.append("Decision accuracy below 0.90; retrain SOP logic and tighten rules.") + if metrics["avg_cost_usd"] and metrics["avg_cost_usd"] > 0.05: + kpi_alerts.append("Cost per task above target ($0.05); optimize model/tool usage.") + + priority_by_risk = { + "normal": [ + "Ship one conversion-focused experiment this week.", + "Automate the highest-frequency manual SOP.", + "Publish one authority-building content asset.", + ], + "elevated": [ + "Freeze low-ROI initiatives and focus on revenue retention.", + "Run churn-prevention outreach for at-risk members.", + "Open a 7-day KPI recovery sprint with a single accountable owner.", + ], + "crisis": [ + "Switch to cash-preservation mode and halt non-critical spend.", + "Activate incident communication plan across all stakeholder channels.", + "Run 24/7 assistant monitoring with 4-hour status updates.", + ], + } + + return { + "identity_core": { + "operator": "7ya.io", + "operating_mode": "single_source_ai_integration", + "strategic_goal": strategic_goal, + "risk_level": risk, + }, + "kpi_snapshot": metrics, + "alerts": kpi_alerts, + "priority_queue": priority_by_risk[risk], + "execution_protocol": { + "context_design": [ + "Global system instructions", + "Project initializer payload", + "Wakeup summary before each new directive", + "Bento-box separation of instructions and data", + ], + "cadence": ["monday_strategy", "wednesday_review", "friday_scoreboard"], + }, + } + def dashboard_html(self) -> str: """Return a basic dashboard HTML for quick product demo.""" metrics = self.get_metrics() @@ -283,6 +348,16 @@ def do_POST(self) -> None: # noqa: N802 self._send_json(module.run_content_repurposing_agent(payload)) return + if self.path == "/api/igor/brief": + module = self._module() + self._send_json( + module.build_igor_assistant_brief( + risk_level=str(payload.get("risk_level", "normal")), + strategic_goal=str(payload.get("strategic_goal", "increase_mrr")), + ) + ) + return + self._send_json({"error": "not found"}, status=404) diff --git a/tests/test_workflow_product_module.py b/tests/test_workflow_product_module.py index 80b4d3c4ed..57edc3b8c3 100644 --- a/tests/test_workflow_product_module.py +++ b/tests/test_workflow_product_module.py @@ -59,3 +59,24 @@ def test_dashboard_contains_kpi_labels(): html = module.dashboard_html() assert "Avg decision accuracy" in html assert "Avg cost / task" in html + + +def test_igor_assistant_brief_contains_execution_protocol_and_identity_core(): + module = WorkflowProductModule() + module.run_lead_qualification_agent( + { + "lead_id": "lead-3", + "budget_usd": 6000, + "decision_authority": "owner", + "need_score": 9, + "timeline_days": 14, + } + ) + + brief = module.build_igor_assistant_brief(risk_level="elevated", strategic_goal="stabilize_churn") + + assert brief["identity_core"]["operating_mode"] == "single_source_ai_integration" + assert brief["identity_core"]["risk_level"] == "elevated" + assert brief["identity_core"]["strategic_goal"] == "stabilize_churn" + assert "context_design" in brief["execution_protocol"] + assert len(brief["priority_queue"]) == 3 From d3ba7d315fb6041b1dc89a5af1ef16871e3ee1ae Mon Sep 17 00:00:00 2001 From: igor vepretski Date: Sat, 18 Apr 2026 18:57:48 +0300 Subject: [PATCH 18/18] Stabilize local run and pytest discovery (#72) --- pytest.ini | 3 +++ src/main.py | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 pytest.ini diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..c7b23ecb14 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +pythonpath = . +testpaths = tests diff --git a/src/main.py b/src/main.py index c99e16b6d6..f8fd1d76d9 100644 --- a/src/main.py +++ b/src/main.py @@ -24,7 +24,15 @@ def main() -> None: # Supported options: Azure OpenAI, GitHub Models, OpenAI API. # See docs/setup.md for detailed configuration instructions. - user_name = input("Enter your name: ") + try: + user_name = input("Enter your name: ").strip() + except EOFError: + user_name = "Builder" + print("Enter your name: [auto] Builder") + + if not user_name: + user_name = "Builder" + print(get_greeting(user_name)) print("\nNext steps:") print(" 1. Read docs/setup.md to configure your environment.")