owenkaplinsky commited on
Commit
363cda9
·
0 Parent(s):

Clean initial commit for HuggingFace

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .github/CONTRIBUTING.md +103 -0
  2. .gitignore +70 -0
  3. Dockerfile +61 -0
  4. LICENSE +674 -0
  5. README.md +403 -0
  6. docker/Dockerfile.candidates_db_init +22 -0
  7. docker/Dockerfile.cv_upload +29 -0
  8. docker/Dockerfile.supervisor +36 -0
  9. docker/Dockerfile.supervisor_api +43 -0
  10. docker/Dockerfile.voice_proxy +29 -0
  11. docker/Dockerfile.voice_screening +28 -0
  12. docker/docker-compose.yml +236 -0
  13. docker/info.md +40 -0
  14. docs/agents/agent_ochestrator.md +0 -0
  15. docs/agents/cv_screening.md +0 -0
  16. docs/agents/google_mcp_agent.md +0 -0
  17. docs/agents/judging_agent.md +0 -0
  18. docs/agents/supervisor/mvps/mvp1/mvp_v1.md +1 -0
  19. docs/agents/supervisor/mvps/mvp2/mvp_v2.md +320 -0
  20. docs/agents/supervisor/mvps/mvp2/single_candidate_mvp.md +257 -0
  21. docs/agents/supervisor/mvps/mvp2/tools_needed.md +110 -0
  22. docs/agents/supervisor/mvps/overview.md +64 -0
  23. docs/agents/supervisor/supervisor_general.md +120 -0
  24. docs/agents/voice_screening.md +336 -0
  25. docs/context_engineering/ideas.md +33 -0
  26. docs/entrypoint_patterns.md +114 -0
  27. docs/how_langgraph_works.md +262 -0
  28. docs/mcp/gmail_mcp_gcp_setup.md +305 -0
  29. docs/mcp/google_tools_mcp.md +180 -0
  30. intro.md +457 -0
  31. langgraph.json +7 -0
  32. package-lock.json +6 -0
  33. requirements/agent.txt +3 -0
  34. requirements/all.txt +64 -0
  35. requirements/api.txt +7 -0
  36. requirements/base.txt +4 -0
  37. requirements/cv_ui.txt +15 -0
  38. requirements/db.txt +4 -0
  39. requirements/mcp_calendar.txt +15 -0
  40. requirements/mcp_gmail.txt +16 -0
  41. requirements/requirements.txt +24 -0
  42. requirements/supervisor.txt +12 -0
  43. requirements/voice_proxy.txt +10 -0
  44. requirements/voice_screening_ui.txt +6 -0
  45. scripts/__init__.py +2 -0
  46. scripts/db/__init__.py +10 -0
  47. scripts/db/debug_all.py +60 -0
  48. scripts/db/list_candidates.py +63 -0
  49. scripts/db/test_connection.py +51 -0
  50. scripts/db/test_session.py +40 -0
.github/CONTRIBUTING.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Contributing Guidelines
2
+
3
+ Welcome to the project! 🎉
4
+ We move fast, but we keep code quality and stability in check.
5
+
6
+ ---
7
+
8
+ ## 🏗️ Branching Model
9
+
10
+ - **main** → Always stable and demo-ready.
11
+ - **dev** → Integration branch.
12
+ - **feature/<name>** → Active development branches.
13
+
14
+ **Flow:**
15
+ 1. Branch off `dev` for your work.
16
+ 2. Open a Pull Request (PR) into `dev`.
17
+ 3. Once `dev` is stable, it’s merged into `main` via a PR + review.
18
+
19
+ Example:
20
+ main ← dev ← feature/email-agent
21
+
22
+
23
+ ---
24
+
25
+ ## ✅ Pull Request Rules
26
+
27
+ - All merges into `main` or `dev` **require at least one approving review**.
28
+ - Keep PRs **small and focused** (<300 lines if possible).
29
+ - Use **clear titles** and **short descriptions** (what + why).
30
+ - You can **open draft PRs early** for feedback.
31
+ - Squash merge when possible to keep history clean.
32
+
33
+ **Naming Convention:**
34
+ - `feat`: add Gmail OAuth flow
35
+ - `fix`: handle missing image extraction
36
+ - `docs`: update setup instructions
37
+
38
+
39
+ ---
40
+
41
+ ## ⚙️ Branch Protection
42
+
43
+ **main**
44
+ - Requires PR review before merging
45
+ - Requires status checks to pass (CI, tests, lint)
46
+ - Must be up-to-date with base before merging
47
+ - No direct commits or force pushes
48
+
49
+ **dev**
50
+ - Requires PR review before merging
51
+ - Requires at least 1 approval
52
+ - Conversations must be resolved
53
+ - Status checks optional (for fast iteration)
54
+ - No direct commits or force pushes
55
+ - Squash or rebase merges only (no merge commits)
56
+
57
+ ---
58
+
59
+ ## 🚀 Quick Workflow
60
+
61
+ 1. `git checkout dev`
62
+ 2. `git pull`
63
+ 3. `git checkout -b feature/my-new-feature`
64
+ 4. Make your changes.
65
+ 5. Push & open a PR → base: `dev`
66
+ 6. Request a review.
67
+ 7. Merge when approved and tests pass.
68
+ 8. Once stable, open a PR from `dev → main`.
69
+
70
+ ---
71
+
72
+ ## 🧹 Hygiene
73
+
74
+ - Delete merged branches.
75
+ - Use Conventional Commits for clarity.
76
+ - Keep `main` always deployable/demo-ready.
77
+ - If you break something, fix it fast 😉
78
+
79
+ ---
80
+
81
+ ## 💬 Reviews
82
+
83
+ - At least **one reviewer** per PR.
84
+ - Anyone can review — small teams move faster.
85
+ - **Pair reviews** encouraged for big changes.
86
+ - Minor changes (docs, comments) may be self-approved if trivial.
87
+
88
+ ---
89
+ ---
90
+
91
+ ## ⚙️ Branch Protection Setup (GitHub Rulesets)
92
+
93
+ You can configure these under
94
+ ➡️ **Settings → Code and automation → Rulesets**
95
+
96
+ | Branch | Require PR | Required Approvals | Require Status Checks | Require Conversation Resolution | Allow Merge Commit | Force Push | Delete Branch |
97
+ | :------ | :----------- | :----------------- | :-------------------- | :------------------------------ | :----------------- | :---------- | :------------- |
98
+ | `main` | ✅ | 1 | ✅ | ✅ | ❌ | ❌ | ❌ |
99
+ | `dev` | ✅ | 1 | optional | ✅ | ❌ | ❌ | ❌ |
100
+
101
+ ---
102
+
103
+ Thanks for contributing — keep it fast, clean, and collaborative! 🚀
.gitignore ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Ignore secret JSONs, not the folder
3
+ secrets/**/credentials.json
4
+ secrets/**/token.json
5
+
6
+ secrets/**/calendar_credentials.json
7
+ secrets/**/calendar_token.json
8
+
9
+ # (Optional) ignore any backup or tmp credentials
10
+ secrets/**/*_backup.json
11
+
12
+ # any log files
13
+ *.log
14
+
15
+ __pycache__/
16
+ *.pyc
17
+
18
+ .env
19
+
20
+ # pycahche files everywhere
21
+ **/__pycache__/
22
+ **/*.pyc
23
+ **/.DS_Store
24
+
25
+
26
+ # data
27
+ src/database/cvs/uploads
28
+ src/database/cvs/parsed
29
+ src/database/voice_recordings
30
+
31
+
32
+
33
+ # Local credentials / tokens
34
+ .gcloud/
35
+ .env
36
+ .env.*
37
+ **/credentials.json
38
+ /results/
39
+
40
+ # Terraform
41
+ .terraform/
42
+ *.tfstate
43
+ *.tfstate.*
44
+ crash.log
45
+ terraform.tfvars
46
+ *.auto.tfvars
47
+ .override.tf
48
+ override.tf
49
+
50
+
51
+ # Ignore only .pdf and .txt files in uploads and parsed folders
52
+ src/database/cvs/uploads/*.pdf
53
+ src/database/cvs/uploads/*.txt
54
+ src/database/cvs/parsed/*.pdf
55
+ src/database/cvs/parsed/*.txt
56
+
57
+ src/database/cvs/tests/*.pdf
58
+ src/database/cvs/tests/*.txt
59
+
60
+ # Keep these files
61
+ !src/database/cvs/uploads/.gitkeep
62
+ !src/database/cvs/parsed/.gitkeep
63
+ !src/database/cvs/uploads/info.md
64
+ !src/database/cvs/parsed/info.md
65
+
66
+ # lamnggraph CLI cache
67
+ .lgcache/
68
+ .langgraph_api/
69
+
70
+ .idea/
Dockerfile ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # System dependencies
6
+ RUN apt-get update && apt-get install -y gcc libpq-dev && rm -rf /var/lib/apt/lists/*
7
+
8
+ # Copy requirement files
9
+ COPY requirements/base.txt requirements/base.txt
10
+ COPY requirements/db.txt requirements/db.txt
11
+ COPY requirements/agent.txt requirements/agent.txt
12
+ COPY requirements/supervisor.txt requirements/supervisor.txt
13
+ COPY requirements/api.txt requirements/api.txt
14
+ COPY requirements/cv_ui.txt requirements/cv_ui.txt
15
+ COPY requirements/mcp_calendar.txt requirements/mcp_calendar.txt
16
+ COPY requirements/mcp_gmail.txt requirements/mcp_gmail.txt
17
+ COPY src/frontend/gradio/requirements.txt requirements/gradio.txt
18
+
19
+ # Install Python dependencies
20
+ RUN pip install --no-cache-dir -r requirements/base.txt \
21
+ && pip install --no-cache-dir -r requirements/db.txt \
22
+ && pip install --no-cache-dir -r requirements/agent.txt \
23
+ && pip install --no-cache-dir -r requirements/supervisor.txt \
24
+ && pip install --no-cache-dir -r requirements/api.txt \
25
+ && pip install --no-cache-dir -r requirements/cv_ui.txt \
26
+ && pip install --no-cache-dir -r requirements/mcp_calendar.txt \
27
+ && pip install --no-cache-dir -r requirements/mcp_gmail.txt \
28
+ && pip install --no-cache-dir -r requirements/gradio.txt
29
+
30
+ # Copy application code
31
+ COPY src/ /app/src/
32
+ COPY secrets/ /app/secrets/
33
+
34
+ ENV PYTHONPATH=/app
35
+ EXPOSE 7860
36
+
37
+ # Create entry script inside the image (avoids missing file in build context)
38
+ RUN printf '%s\n' \
39
+ '#!/usr/bin/env bash' \
40
+ 'set -e' \
41
+ '' \
42
+ '# Hugging Face provides PORT; default to 7860 locally' \
43
+ 'export PORT=\"${PORT:-7860}\"' \
44
+ '' \
45
+ '# Defaults for local in-container routing; can be overridden via env' \
46
+ 'export SUPERVISOR_API_URL=\"${SUPERVISOR_API_URL:-http://127.0.0.1:8080/api/v1/supervisor}\"' \
47
+ 'export DATABASE_API_URL=\"${DATABASE_API_URL:-http://127.0.0.1:8080/api/v1/db}\"' \
48
+ 'export CV_UPLOAD_API_URL=\"${CV_UPLOAD_API_URL:-http://127.0.0.1:8080/api/v1/cv}\"' \
49
+ '' \
50
+ '# Start FastAPI backend' \
51
+ 'uvicorn src.api.app:app --host 0.0.0.0 --port 8080 &' \
52
+ '' \
53
+ '# Give the API a moment to come up' \
54
+ 'sleep 2' \
55
+ '' \
56
+ '# Run Gradio frontend' \
57
+ 'python src/frontend/gradio/app.py' \
58
+ > /app/start.sh \
59
+ && chmod +x /app/start.sh
60
+
61
+ CMD ["/app/start.sh"]
LICENSE ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <https://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <https://www.gnu.org/licenses/why-not-lgpl.html>.
README.md ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ***`Recruitment Agent`***
2
+ <p align="left">
3
+ <img src="https://img.shields.io/badge/MCP%20Hackathon-Track%202%20%E2%80%94%20Enterprise-blue" />
4
+ <img src="https://img.shields.io/badge/Model%20Context%20Protocol-Enabled-green" />
5
+ <img src="https://img.shields.io/badge/AI%20Agents-Recruitment-orange" />
6
+ <img src="https://img.shields.io/badge/Python-3.10%2B-blue" />
7
+ <img src="https://img.shields.io/badge/LangGraph-Agent%20Orchestration-purple" />
8
+ <img src="https://img.shields.io/badge/Gradio-UI%20Interface-yellow" />
9
+ <img src="https://img.shields.io/badge/HuggingFace-Platform%20%26%20Hackathon-black?logo=huggingface" />
10
+ <img src="https://img.shields.io/badge/OpenAI-LLM%20Powered-0A0A23?logo=openai" />
11
+ <img src="https://img.shields.io/badge/Google%20Cloud-APIs%20%26%20MCP%20Tools-blue?logo=googlecloud" />
12
+ </p>
13
+
14
+
15
+
16
+
17
+
18
+
19
+ > This project was developed as part of the **[MCP 1st Birthday Hackathon](https://huggingface.co/MCP-1st-Birthday)** — submitted under
20
+ > **Track 2: MCP in Action (Enterprise)**, showcasing a real-world multi-agent application built on top of the Model Context Protocol.
21
+
22
+
23
+ <details>
24
+ <summary><strong>📚 Table of Contents</strong> (click to expand)</summary>
25
+
26
+ - [Problem Statement](#problem-statement)
27
+ - [Ethical & Regulatory Considerations](#ethical--regulatory-considerations)
28
+ - [Quick Start: Run Application](#quick-start-run-application)
29
+ - [Services & Ports](#services--ports)
30
+ - [Infrastructure & Secrets](#infrastructure--secrets)
31
+ - [Run Command](#run-command)
32
+ - [Resetting the Environment](#resetting-the-environment)
33
+ - [Application Flow & Entry Points](#application-flow--entry-points)
34
+ - [The Recruitment Lifecycle](#1-the-recruitment-lifecycle)
35
+ - [User Entry Points](#2-user-entry-points)
36
+ - [AI Engineering Principles](#ai-engineering-principles)
37
+ - [Prompt Engineering](#prompt-engineering)
38
+ - [Context Engineering](#context-engineering)
39
+ - [Model & Agent Registry](#model--agent-registry)
40
+ - [Integrated MCP Servers](#integrated-mcp-servers)
41
+ - [License & Acknowledgments](#license--acknowledgments)
42
+ - [Team](#team)
43
+
44
+ </details>
45
+
46
+
47
+
48
+
49
+ ## **Problem Statement**
50
+
51
+ Modern recruitment processes remain **slow**, **resource-intensive**, and increasingly **unsustainable** for HR teams amid persistent talent shortages and evolving skill demands. Recent industry reports underscore structural bottlenecks that hinder efficient hiring.
52
+
53
+ High **applicant volumes overwhelm recruiters**, with a *typical job posting attracting hundreds of applications*, many *unqualified*, leading to administrative burdens and rushed evaluations. This results in *only about **5%** of viewers completing applications*, while teams waste time sifting through low-quality submissions. [`1`]
54
+
55
+ Screening and early-stage evaluation consume excessive recruiter time, with **35%** of their efforts dedicated to tasks like interview scheduling alone, exacerbating workload pressures. Talent acquisition leaders report unmanageable demands, with **27%** citing overload as a key issue, up from prior years. [`2`]
56
+
57
+ **Hiring timelines average 44 days across industries**, driven by skills mismatches and manual processes that delay filling critical roles. Globally, **76%** of employers struggle to fill positions due to talent gaps, particularly in tech and healthcare sectors. [`1`, `3`]
58
+
59
+ The financial toll is significant, with **average cost-per-hire reaching $4,700**, fueled by prolonged cycles, high turnover in recruitment teams (projected at **51%** as a top 2025 challenge), and inefficiencies in sourcing. [`1`, `2`]
60
+
61
+ HR professionals **face rising burnout** from these pressures, compounded by competition for diverse talent and the **need for more touchpoints in hiring**, which **45%** of leaders say adds complexity. Skills shortages, cited by **63%** of employers as the primary barrier to growth, further strain teams. [`2`, `4`]
62
+
63
+ These challenges reveal that **traditional manual recruitment fails to scale** in a competitive 2025 landscape. An AI-driven recruitment agent can alleviate bottlenecks by automating screening, accelerating timelines, enhancing consistency, and allowing HR to prioritize strategic decisions over repetitive tasks.
64
+
65
+
66
+
67
+ ### *`References`*
68
+
69
+ 1. [HR Cloud — 25 Recruitment Challenges & Solutions in 2025](https://www.hrcloud.com/blog/recruitment-challenges)
70
+
71
+ 2. [Select Software Reviews — 100+ Recruitment Statistics Every HR Should Know in 2025](https://www.selectsoftwarereviews.com/blog/recruiting-statistics)
72
+
73
+ 3. [Social Talent — The 2025 Hiring Reality Check](https://www.socialtalent.com/leadership/the-2025-hiring-reality-check-data-driven-answers-to-ta-leaders-top-questions)
74
+
75
+ 4. [World Economic Forum — The Future of Jobs Report 2025](https://www.weforum.org/publications/the-future-of-jobs-report-2025/digest/)
76
+
77
+ ## **Ethical & Regulatory Considerations**
78
+
79
+ This project was developed as an **experimental prototype for a hackathon**, designed to showcase how language-model agents can automate structured workflows. It is **not intended for production deployment** as an autonomous hiring system. Because it touches on the automated assessment of humans, it must be approached with caution and interpreted within the correct ethical and regulatory context.
80
+
81
+ The risks of algorithmic profiling have been widely documented, most notably during the **Cambridge Analytica scandal**, where data from millions of users was harvested and used for psychographic targeting without consent. This episode demonstrated how data-driven models can be leveraged to manipulate individuals when used irresponsibly, and it significantly shaped today’s regulatory landscape. [`5`]
82
+
83
+ Given this history, any system that evaluates or ranks people—particularly in employment—must uphold **strict transparency, human oversight, and narrow scope**. In this prototype, all AI outputs are intended purely as **assistive signals**. The system must **never** be used to autonomously approve, reject, or shortlist candidates.
84
+
85
+ The **EU AI Act** classifies AI systems used for recruitment, CV screening, candidate ranking, promotion decisions, or termination as **High-Risk AI Systems** (Annex III). Such systems are permitted in the EU but must meet stringent requirements, including:
86
+
87
+ - **Human oversight** with the ability to override AI suggestions
88
+ - **Transparency** about the model’s role and limitations
89
+ - **Detailed logging and traceability** of system behavior
90
+ - **Bias monitoring and risk management**
91
+ - **High-quality and relevant training data**
92
+ - **Clear separation** between AI scoring and final human judgment
93
+
94
+ The Act also **prohibits** certain practices in hiring, such as emotion recognition in workplace settings, biometric inference of personality traits, and social-scoring-style ranking systems. [`6`, `7`, `8`]
95
+
96
+ This prototype **does not** conduct emotion recognition, sensitive-trait inference, biometric profiling, or psychographic prediction. It is a technical experiment focused on agent orchestration, workflow automation, and context management—not an end-to-end HR decision engine.
97
+
98
+ ### **Human-in-the-Loop by Design**
99
+ To remain aligned with ethical expectations and regulatory requirements, this system must always operate with:
100
+
101
+ - **Human-in-the-Loop (HITL):** Recruiters make all decisions.
102
+ - **Explainability:** Agents produce structured rationales, not black-box judgments.
103
+ - **Data minimization:** Only job-relevant information is processed.
104
+ - **No profiling of protected traits:** No biometric, psychographic, or emotional inference.
105
+
106
+ ### **Project Status**
107
+ This project remains a **research and demonstration artifact**, created to explore the technical viability of LLM-powered coordination between agents. It highlights what is technologically possible, but is **not a deployable HR solution** under the EU AI Act. Any real-world implementation would require extensive risk assessment, compliance measures, and human oversight to avoid replicating the harms demonstrated in past profiling scandals.
108
+
109
+ ---
110
+
111
+ ### *`References`*
112
+
113
+ 5. [The Guardian — Cambridge Analytica: A Year On, Lesson in Institutional Failure](https://www.theguardian.com/uk-news/2019/mar/17/cambridge-analytica-year-on-lesson-in-institutional-failure-christopher-wylie)
114
+
115
+ 6. [High-level summary of the EU AI Act](https://artificialintelligenceact.eu/high-level-summary/)
116
+
117
+ 7. [EU Digital Strategy — Regulatory Framework for AI](https://digital-strategy.ec.europa.eu/en/policies/regulatory-framework-ai)
118
+
119
+ 8. [Clifford Chance — What Does the EU AI Act Mean for Employers?](https://www.cliffordchance.com/content/dam/cliffordchance/briefings/2024/08/what-does-the-eu-ai-act-mean-for-employers.pdf)
120
+
121
+
122
+
123
+ ## ***`Quick Start: Run Application`***
124
+ To spin up the entire platform including the database, agents, and UI dashboards, we use **Docker Compose**.
125
+
126
+ ### ***Services & Ports***
127
+ | Service | Description | Host Port | Container Port |
128
+ |---------|-------------|-----------|----------------|
129
+ | `db` | PostgreSQL 15 database with persistent storage | **5433** | 5432 |
130
+ | `cv_upload_streamlit` | UI for uploading CVs | **8501** | 8501 |
131
+ | `voice_screening_streamlit` | UI for voice screening candidates | **8502** | 8501 |
132
+ | `supervisor_ui` | Main Chat UI for the Supervisor Agent | **8503** | 8501 |
133
+ | `websocket_proxy` | Proxy for OpenAI Realtime API | **8000** | 8000 |
134
+
135
+ ### ***Infrastructure & Secrets***
136
+ This project requires Google Cloud credentials for the Gmail and Calendar agents.
137
+
138
+ - **Secrets:** Google tokens and credentials must be present in the `secrets/` directory.
139
+ - **Infrastructure:** You can provision the necessary GCP infrastructure using the code in `terraform/` or the scripts in `scripts/infra/`.
140
+ - **Documentation:** For detailed setup instructions, refer to the [MCP Docs](docs/mcp/).
141
+
142
+ ### ***Run Command***
143
+ 1. **Configure Environment:**
144
+ Copy the example environment file and fill in your API keys:
145
+ ```bash
146
+ cp .env.example .env
147
+ ```
148
+
149
+ 2. **Start Services:**
150
+ ```bash
151
+ docker compose --env-file .env -f docker/docker-compose.yml up --build
152
+ ```
153
+
154
+ ### 🧹 Resetting the Environment
155
+ If you need a clean slate (e.g., after modifying DB models):
156
+ ```bash
157
+ # 1. Stop containers
158
+ docker compose -f docker/docker-compose.yml down
159
+
160
+ # 2. Remove persistent DB volume
161
+ docker volume rm docker_postgres_data
162
+
163
+ # 3. Rebuild & Start
164
+ docker compose --env-file .env -f docker/docker-compose.yml up --build
165
+ ```
166
+
167
+ ---
168
+
169
+ ## ***`Application Flow & Entry Points`***
170
+
171
+ The platform orchestrates a complete recruitment pipeline, interacting with both Candidates and the HR Supervisor.
172
+
173
+ ### 1. The Recruitment Lifecycle
174
+ The system tracks candidates through a defined state machine (see `src/state/candidate.py` for the `CandidateStatus` enum).
175
+
176
+ ```mermaid
177
+ graph TD
178
+ %% Actors
179
+ Candidate((Candidate))
180
+ HR((HR Supervisor))
181
+
182
+ %% System Components (Nodes)
183
+ CV_UI[CV Portal UI]
184
+ CV_Screen{CV Screening AI}
185
+ Voice_UI[Voice Portal UI]
186
+ Voice_Judge{Voice Judge AI}
187
+ Interview[Person-to-Person Interview]
188
+ Decision{Final Decision}
189
+
190
+ %% Flow & Actions (Edges)
191
+ Candidate -->|1. Uploads CV| CV_UI
192
+ CV_UI -->|2. Triggers Analysis| CV_Screen
193
+
194
+ CV_Screen -->|Pass: Sends Invite| Voice_UI
195
+ CV_Screen -->|Fail: Notify| Rejected((Rejected))
196
+
197
+ Voice_UI -->|3. Conducts Interview| Candidate
198
+ Candidate -->|4. Completes Session| Voice_Judge
199
+
200
+ Voice_Judge -->|Pass: Schedule| Interview
201
+ Voice_Judge -->|Fail: Notify| Rejected
202
+
203
+ Interview -->|5. Feedback| HR
204
+ HR -->|6. Updates Status| Decision
205
+
206
+ Decision -->|Hire| Hired((Hired))
207
+ Decision -->|Reject| Rejected
208
+
209
+ %% Styling
210
+ style CV_UI fill:#e3f2fd,stroke:#1565c0
211
+ style Voice_UI fill:#e3f2fd,stroke:#1565c0
212
+ style CV_Screen fill:#fff3e0,stroke:#ef6c00
213
+ style Voice_Judge fill:#fff3e0,stroke:#ef6c00
214
+ style Interview fill:#e8f5e9,stroke:#2e7d32
215
+ style Decision fill:#f3e5f5,stroke:#7b1fa2
216
+ ```
217
+
218
+ ### 2. User Entry Points
219
+
220
+ | User | Interface | Port | Description |
221
+ | :--- | :--- | :--- | :--- |
222
+ | **HR Manager** | **Supervisor UI** | `8503` | **The Command Center.** Chat with the Supervisor Agent to manage the pipeline, review candidates, query the DB, and schedule interviews. |
223
+ | **Candidate** | **CV Portal** | `8501` | Public-facing portal for candidates to register and upload their resumes to the system. |
224
+ | **Candidate** | **Voice Portal** | `8502` | AI-conducted voice interview interface. Candidates access this only after passing CV screening and receiving an invite. |
225
+
226
+ ---
227
+
228
+ ## ***`AI Engineering Principles`***
229
+
230
+ ### ***Prompt Engineering***
231
+
232
+ To improve the reliability of complex evaluations (such as CV scoring and Voice Interview judging), we enforce **Chain-of-Thought (CoT)** reasoning within our structured outputs, inspired by [Wei et al. (2022)](https://arxiv.org/abs/2201.11903).
233
+
234
+ By requiring the model to generate a textual explanation *before* assigning numerical scores, we ensure the model "thinks" through the evidence before committing to a decision. This is implemented directly in our Pydantic schemas (e.g., `src/agents/cv_screening/schemas/output_schema.py`), where field order matters:
235
+
236
+ ```mermaid
237
+ flowchart LR
238
+ %% Nodes
239
+ Input[Input Data]
240
+ subgraph "Structured Output Schema"
241
+ Feedback["1. Generate Feedback (CoT)"]
242
+ Score["2. Assign Scores"]
243
+ end
244
+ Output[Overall Score]
245
+
246
+ %% Flow
247
+ Input --> Feedback
248
+ Feedback --> Score
249
+ Score --> Output
250
+
251
+ %% Styling
252
+ style Feedback fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
253
+ style Score fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
254
+ ```
255
+
256
+ This simple structural constraint leads to significantly better calibration and reduced hallucination in scoring.
257
+
258
+ ### ***Context Engineering***
259
+
260
+ To ensure long-running reliability and precision, this system employs a multi-layered approach to context management. This architecture prevents **"Context Rot"**—a phenomenon where LLM performance degrades as input length increases, as highlighted in [Chroma's research](https://research.trychroma.com/context-rot). By managing context effectively, we ensure agents remain focused and accurate over extended interactions.
261
+
262
+
263
+ #### 1. Context Isolation via Delegation
264
+ Instead of a single monolithic agent, tasks are delegated to **specialized sub-agents** (e.g., `cv_screener`, `voice_screener`).
265
+
266
+ - **Delegate (Solid Arrow):** The Supervisor initiates a task, passing only the necessary context to a specific sub-agent.
267
+ - **Report Back (Dotted Arrow):** Once the sub-agent completes its task, it returns a structured summary to the Supervisor, ensuring the main context remains clean.
268
+
269
+ ```mermaid
270
+ graph TD
271
+ %% Legend (Top)
272
+ subgraph Legend [Legend]
273
+ direction LR
274
+ KeySup[Supervisor] -->|Delegation| KeyAgent[Sub-Agent]
275
+ KeyAgent -.->|Report Back| KeySup
276
+ end
277
+
278
+ %% Force Legend to be above Supervisor
279
+ Legend ~~~ Supervisor
280
+
281
+ Supervisor[🤖 Supervisor Agent]
282
+
283
+ %% Sub-Agents
284
+ Gmail[📧 Gmail Agent]
285
+ Cal[📅 GCalendar Agent]
286
+ DBExec[💾 DB Executor]
287
+ CV[📄 CV Screener]
288
+ Voice[🎤 Voice Screener]
289
+
290
+ %% Delegation (Outbound)
291
+ Supervisor --> Gmail
292
+ Supervisor --> Cal
293
+ Supervisor --> DBExec
294
+ Supervisor --> CV
295
+ Supervisor --> Voice
296
+
297
+ %% Feedback (Inbound)
298
+ Gmail -.-> Supervisor
299
+ Cal -.-> Supervisor
300
+ DBExec -.-> Supervisor
301
+ CV -.-> Supervisor
302
+ Voice -.-> Supervisor
303
+
304
+ %% Styling
305
+ style Supervisor fill:#e1bee7,stroke:#4a148c,stroke-width:2px
306
+ style Gmail fill:#fff3e0,stroke:#e65100
307
+ style Cal fill:#fff3e0,stroke:#e65100
308
+ style DBExec fill:#fff3e0,stroke:#e65100
309
+ style CV fill:#e3f2fd,stroke:#1565c0
310
+ style Voice fill:#e3f2fd,stroke:#1565c0
311
+ style Legend fill:#f5f5f5,stroke:#9e9e9e,stroke-dasharray: 5 5
312
+ ```
313
+
314
+ - **How it works:** Each *sub-agent* operates in its *own isolated context/thread*.
315
+ - **Benefit:** The main Supervisor is not polluted with low-level execution logs. Sub-agents are **stateless** from the Supervisor's perspective—each trigger starts a fresh thread, preventing error accumulation in the workers.
316
+
317
+
318
+ #### 2. Context Offloading & Loading (RAG-lite)
319
+ We treat the database not just as storage, but as **offloaded context**.
320
+ - **Offloading:** Candidate data, screening results, and interview states are persisted immediately to a structured SQL/JSON database.
321
+ - **Loading:** The Supervisor does not keep all candidate data in memory. Instead, it utilizes the `db_executor` agent to **retrieve (load)** only the specific data points needed for the current planning step.
322
+ - **Benefit:** Keeps the active context window lean and focused on *reasoning* rather than *storage*.
323
+
324
+ #### 3. Adaptive Context Compaction
325
+ For the **stateful Supervisor** (which manages the long-running user conversation), we implement **Compactive Summarization**.
326
+ - **Mechanism:** As the conversation history exceeds a token threshold, older interactions are summarized into a concise narrative while recent messages are kept verbatim.
327
+ - **Result:** The agent retains "long-term memory" of the conversation arc without hitting context window limits, keeping the Supervisor "forever young."
328
+
329
+ ```mermaid
330
+ graph TD
331
+ User[User / API] -->|Long-running Thread| Supervisor
332
+
333
+ subgraph "Stateful & Compacted"
334
+ Supervisor[Supervisor Agent]
335
+ Memory[Context Compaction Module] -.->|Summarizes History| Supervisor
336
+ end
337
+
338
+ subgraph "Stateless & Isolated"
339
+ CV[CV Screener]
340
+ Voice[Voice Screener]
341
+ end
342
+
343
+ subgraph "Context Offloading"
344
+ DB[(Postgres DB)]
345
+ end
346
+
347
+ Supervisor -->|Delegates Task| CV
348
+ Supervisor -->|Delegates Task| Voice
349
+ Supervisor -->|Queries/Updates| DB
350
+
351
+ CV -.->|1. New Thread| CV
352
+ Voice -.->|1. New Thread| Voice
353
+ ```
354
+
355
+ ## ***`Model & Agent Registry`***
356
+
357
+ A breakdown of the various LLMs, Agents, and Workflows powering the system.
358
+
359
+ - 🤖 **Agent:** Autonomous entity that can use tools, plan multiple steps, and maintain reasoning loops.
360
+ - ⚙️ **Workflow:** Deterministic, fixed sequence of operations (Pipeline). It may use LLMs for specific steps but the flow is hardcoded.
361
+ - 🧠 **Simple LLM:** A direct "one-shot" call to a Language Model for a specific transformation (e.g., summarization, extraction) without tools or loops.
362
+
363
+ | Component | Type | Model | Description | Location |
364
+ | :--- | :--- | :--- | :--- | :--- |
365
+ | **Supervisor Agent** | 🤖 **Agent** | `gpt-4o` | Orchestrates delegation, planning, and context management. | `src/agents/supervisor/supervisor_v2.py` |
366
+ | **Gmail Agent** | 🤖 **Agent** | `gpt-4o` | Autonomous email management via MCP (read/send/label). | `src/agents/gmail/gmail_agent.py` |
367
+ | **GCalendar Agent** | 🤖 **Agent** | `gpt-4o` | Autonomous calendar scheduling via MCP. | `src/agents/gcalendar/gcalendar_agent.py` |
368
+ | **DB Executor** | 🤖 **Agent** | `gpt-4o` | Writes SQL/Python to query the database (CodeAct). | `src/agents/db_executor/db_executor.py` |
369
+ | **CV Screening** | ⚙️ **Workflow** | `gpt-4o` | Deterministic pipeline: Fetch → Read → Evaluate → Save. | `src/agents/cv_screening/cv_screening_workflow.py` |
370
+ | **Voice Judge** | 🧠 **Simple LLM** | `gpt-4o-audio` | Evaluates audio/transcripts for sentiment & confidence. | `src/agents/voice_screening/judge.py` |
371
+ | **Doc Parser** | 🧠 **Simple LLM** | `gpt-4o-mini` | Vision-based PDF-to-Markdown conversion. | `src/doc_parser/pdf_to_markdown.py` |
372
+ | **History Manager** | 🧠 **Simple LLM** | `gpt-4o-mini` | Summarizes conversation history for context compaction. | `src/context_eng/history_manager.py` |
373
+
374
+ ### 🔌 ***`Integrated MCP Servers`***
375
+ The system integrates **Model Context Protocol (MCP)** servers to securely and standardizedly connect agents to external tools.
376
+
377
+ | MCP Server | Purpose | Used By |
378
+ | :--- | :--- | :--- |
379
+ | **Gmail MCP** | Provides tools to `list`, `read`, `send`, and `label` emails. | `Gmail Agent` |
380
+ | **Google Calendar MCP** | Provides tools to `list_events`, `create_event`, and `update_event`. | `GCalendar Agent` |
381
+
382
+ > **Note:** Each MCP server runs as a standalone process that exposes a standardized tool interface, which the respective agent consumes dynamically.
383
+
384
+ ---
385
+
386
+ ## ***`License & Acknowledgments`***
387
+ This project utilizes code from:
388
+ - [gmail-mcp](https://github.com/theposch/gmail-mcp) by **theposch** (GPLv3)
389
+ *Integrated at:* `src/mcp_servers/gmail-mcp/`
390
+ - [calendar-mcp](https://github.com/deciduus/calendar-mcp) by **deciduus** (AGPL-3.0)
391
+ *Integrated at:* `src/mcp_servers/calendar-mcp/`
392
+
393
+ We deeply acknowledge these original works and the great AI and Data Science community that makes such collaboration possible. We distribute our modifications under the compatible license terms.
394
+
395
+ ---
396
+
397
+ ## 👥 ***`Team`***
398
+ | Member |
399
+ | -------- |
400
+ | [Sebastian Wefers](https://github.com/Ocean-code-1995) |
401
+ | [Dmitri Moscoglo](https://github.com/DimiM99) |
402
+ | [Owen Kaplinsky](https://github.com/owenkaplinsky) |
403
+ | [SrikarMK](https://github.com/Srikarmk) |
docker/Dockerfile.candidates_db_init ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --- Dockerfile.candidates_db_init ---
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory inside container
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies needed for psycopg2
8
+ RUN apt-get update && apt-get install -y \
9
+ libpq-dev gcc && \
10
+ rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy requirements file and install dependencies
13
+
14
+ COPY ../requirements/base.txt ./requirements/base.txt
15
+ COPY ../requirements/db.txt ./requirements/db.txt
16
+ RUN pip install --no-cache-dir -r requirements/db.txt
17
+
18
+ # Copy *only* the candidate database module
19
+ COPY src/database/candidates ./src/database/candidates
20
+
21
+ # Default command - use dedicated init script to avoid circular import
22
+ CMD ["python", "-m", "src.database.candidates.init_db"]
docker/Dockerfile.cv_upload ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python slim base
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ libpq-dev gcc && \
10
+ rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy only requirements first (for build caching)
13
+ COPY ../requirements/base.txt ./requirements/base.txt
14
+ COPY ../requirements/db.txt ./requirements/db.txt
15
+ COPY ../requirements/cv_ui.txt ./requirements/cv_ui.txt
16
+ # Install Streamlit + base deps
17
+ RUN pip install --no-cache-dir -r requirements/cv_ui.txt
18
+
19
+ # Copy project source code
20
+ COPY ../src ./src
21
+
22
+ ENV PYTHONPATH=/app
23
+
24
+
25
+ # Expose Streamlit port
26
+ EXPOSE 8501
27
+
28
+ # Default command to run Streamlit app
29
+ CMD ["streamlit", "run", "src/frontend/streamlit/cv_ui/app.py", "--server.port=8501", "--server.address=0.0.0.0"]
docker/Dockerfile.supervisor ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ gcc \
8
+ libpq-dev \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirement files
12
+ COPY requirements/base.txt requirements/base.txt
13
+ COPY requirements/db.txt requirements/db.txt
14
+ COPY requirements/agent.txt requirements/agent.txt
15
+ COPY requirements/supervisor.txt requirements/supervisor.txt
16
+ COPY requirements/mcp_calendar.txt requirements/mcp_calendar.txt
17
+
18
+ # Install dependencies directly (no venv needed in container)
19
+ # **NOTE** uv isntallation is needed for the gmail mcp server to work.
20
+ # >>> it is installed in the base image /usr/local/bin/uv
21
+ RUN pip install --no-cache-dir uv && \
22
+ pip install --no-cache-dir -r requirements/supervisor.txt && \
23
+ pip install --no-cache-dir -r requirements/db.txt && \
24
+ pip install --no-cache-dir -r requirements/agent.txt && \
25
+ pip install --no-cache-dir -r requirements/mcp_calendar.txt
26
+
27
+ # Copy application code
28
+ COPY src/ /app/src/
29
+ COPY secrets/ /app/secrets/
30
+ COPY .env /app/.env
31
+
32
+ # Expose Streamlit port
33
+ EXPOSE 8501
34
+
35
+ # Run Streamlit
36
+ CMD ["streamlit", "run", "src/frontend/streamlit/supervisor_ui/app.py", "--server.port=8501", "--server.address=0.0.0.0"]
docker/Dockerfile.supervisor_api ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ gcc \
8
+ libpq-dev \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirement files
12
+ COPY requirements/base.txt requirements/base.txt
13
+ COPY requirements/db.txt requirements/db.txt
14
+ COPY requirements/agent.txt requirements/agent.txt
15
+ COPY requirements/supervisor.txt requirements/supervisor.txt
16
+ COPY requirements/api.txt requirements/api.txt
17
+ COPY requirements/cv_ui.txt requirements/cv_ui.txt
18
+ COPY requirements/mcp_calendar.txt requirements/mcp_calendar.txt
19
+ COPY requirements/mcp_gmail.txt requirements/mcp_gmail.txt
20
+
21
+ # Install dependencies directly (no venv needed in container)
22
+ # **NOTE** uv installation is needed for the gmail mcp server to work.
23
+ # >>> it is installed in the base image /usr/local/bin/uv
24
+ RUN pip install --no-cache-dir uv && \
25
+ pip install --no-cache-dir -r requirements/supervisor.txt && \
26
+ pip install --no-cache-dir -r requirements/db.txt && \
27
+ pip install --no-cache-dir -r requirements/agent.txt && \
28
+ pip install --no-cache-dir -r requirements/api.txt && \
29
+ pip install --no-cache-dir -r requirements/cv_ui.txt && \
30
+ pip install --no-cache-dir -r requirements/mcp_calendar.txt && \
31
+ pip install --no-cache-dir -r requirements/mcp_gmail.txt
32
+
33
+ # Copy application code
34
+ COPY src/ /app/src/
35
+ COPY secrets/ /app/secrets/
36
+ COPY .env /app/.env
37
+
38
+ # Expose API port
39
+ EXPOSE 8080
40
+
41
+ # Run FastAPI with uvicorn
42
+ CMD ["uvicorn", "src.api.app:app", "--host", "0.0.0.0", "--port", "8080"]
43
+
docker/Dockerfile.voice_proxy ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python slim base
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ libpq-dev gcc && \
10
+ rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy only requirements first (for build caching)
13
+ COPY ../requirements/base.txt ./requirements/base.txt
14
+ COPY ../requirements/db.txt ./requirements/db.txt
15
+ COPY ../requirements/voice_proxy.txt ./requirements/voice_proxy.txt
16
+ # Install Streamlit + base deps
17
+ RUN pip install --no-cache-dir -r requirements/voice_proxy.txt
18
+
19
+ # Copy project source code
20
+ COPY ../src ./src
21
+
22
+ ENV PYTHONPATH=/app
23
+
24
+
25
+ # Expose FastAPI port
26
+ EXPOSE 8000
27
+
28
+ # Default command to run FastAPI proxy
29
+ CMD ["python", "-m", "uvicorn", "src.frontend.streamlit.voice_screening_ui.proxy:app", "--host", "0.0.0.0", "--port", "8000"]
docker/Dockerfile.voice_screening ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python slim base
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y \
9
+ libpq-dev gcc && \
10
+ rm -rf /var/lib/apt/lists/*
11
+
12
+ # Copy only requirements first (for build caching)
13
+ COPY ../requirements/base.txt ./requirements/base.txt
14
+ COPY ../requirements/voice_screening_ui.txt ./requirements/voice_screening_ui.txt
15
+ # Install Streamlit + base deps
16
+ RUN pip install --no-cache-dir -r requirements/voice_screening_ui.txt
17
+
18
+ # Copy project source code
19
+ COPY ../src ./src
20
+
21
+ ENV PYTHONPATH=/app
22
+
23
+
24
+ # Expose Streamlit port
25
+ EXPOSE 8501
26
+
27
+ # Default command to run Streamlit app
28
+ CMD ["streamlit", "run", "src/frontend/streamlit/voice_screening_ui/app.py", "--server.port=8501", "--server.address=0.0.0.0"]
docker/docker-compose.yml ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
2
+ # Run as follows from root:
3
+ # >>> docker compose --env-file .env -f docker/docker-compose.yml up --build
4
+ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
5
+
6
+ services:
7
+ # --- Database Service ---
8
+ # Runs a PostgreSQL 15 instance with persistent storage.
9
+ db:
10
+ image: postgres:15
11
+ container_name: agentic_hr_db
12
+ restart: always
13
+ ports:
14
+ - "5433:5432"
15
+ volumes:
16
+ - postgres_data:/var/lib/postgresql/data
17
+ healthcheck:
18
+ test: ["CMD-SHELL", "pg_isready -U agentic_user -d agentic_hr"]
19
+ interval: 3s
20
+ timeout: 3s
21
+ retries: 5
22
+ environment:
23
+ POSTGRES_HOST: ${POSTGRES_HOST}
24
+ POSTGRES_PORT: ${POSTGRES_PORT}
25
+ POSTGRES_USER: ${POSTGRES_USER}
26
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
27
+ POSTGRES_DB: ${POSTGRES_DB}
28
+ networks:
29
+ - hrnet
30
+
31
+ candidates_db_init:
32
+ # --- Application Service ---
33
+ # Runs your Python backend inside Docker.
34
+ # Initializes the database or starts the API (depending on command).
35
+ container_name: candidates_db_init
36
+ build:
37
+ context: .. # build from the project root
38
+ dockerfile: docker/Dockerfile.candidates_db_init
39
+ depends_on:
40
+ db:
41
+ condition: service_healthy
42
+ environment:
43
+ POSTGRES_HOST: ${POSTGRES_HOST}
44
+ POSTGRES_PORT: ${POSTGRES_PORT}
45
+ POSTGRES_USER: ${POSTGRES_USER}
46
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
47
+ POSTGRES_DB: ${POSTGRES_DB}
48
+ # command: ["python", "-m", "src.database.candidates.init_db"]
49
+
50
+ volumes:
51
+ # --- Local code mount (for development only) ---
52
+ # Mounts your entire project source from the host (../)
53
+ # into the container at /app.
54
+ # ✅ Enables live code changes without rebuilding the image.
55
+ # ⚠️ Do NOT use in production – overrides the built image code.
56
+ - ../:/app # optional: live reload for local dev
57
+
58
+ networks:
59
+ - hrnet
60
+
61
+ # --- CV Upload ---
62
+ cv_upload_streamlit:
63
+ container_name: cv_upload_streamlit
64
+ build:
65
+ context: ..
66
+ dockerfile: docker/Dockerfile.cv_upload
67
+ ports:
68
+ - "8501:8501"
69
+ depends_on:
70
+ - db
71
+ - supervisor_api
72
+ environment:
73
+ # Database connection
74
+ POSTGRES_HOST: ${POSTGRES_HOST}
75
+ POSTGRES_PORT: ${POSTGRES_PORT}
76
+ POSTGRES_USER: ${POSTGRES_USER}
77
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
78
+ POSTGRES_DB: ${POSTGRES_DB}
79
+ DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
80
+ CV_UPLOAD_PATH: /app/src/database/cvs/uploads
81
+ # App specific
82
+ CV_UPLOAD_API_URL: http://supervisor_api:8080/api/v1/cv
83
+ PYTHONPATH: /app
84
+ volumes:
85
+ # Mount local code for live updates
86
+ - ../:/app
87
+ # Shared volume for CV uploads (persistent)
88
+ - ../src/database/cvs:/app/src/database/cvs
89
+ command:
90
+ [
91
+ "streamlit",
92
+ "run",
93
+ "src/frontend/streamlit/cv_ui/app.py",
94
+ "--server.port=8501",
95
+ "--server.address=0.0.0.0",
96
+ ]
97
+ networks:
98
+ - hrnet
99
+
100
+ # --- WebSocket Proxy for OpenAI Realtime API ---
101
+ websocket_proxy:
102
+ container_name: websocket_proxy
103
+ build:
104
+ context: ..
105
+ dockerfile: docker/Dockerfile.voice_proxy
106
+ ports:
107
+ - "8000:8000"
108
+ depends_on:
109
+ - db
110
+ - candidates_db_init
111
+ environment:
112
+ PYTHONPATH: /app
113
+ OPENAI_API_KEY: ${OPENAI_API_KEY}
114
+ BACKEND_API_URL: http://supervisor_api:8080
115
+ volumes:
116
+ # Mount local code for live updates
117
+ - ../:/app
118
+ command:
119
+ [
120
+ "python",
121
+ "-m",
122
+ "uvicorn",
123
+ "src.frontend.streamlit.voice_screening_ui.proxy:app",
124
+ "--host",
125
+ "0.0.0.0",
126
+ "--port",
127
+ "8000",
128
+ ]
129
+ networks:
130
+ - hrnet
131
+
132
+ # --- Voice Screening UI ---
133
+ voice_screening_ui:
134
+ container_name: voice_screening_ui
135
+ build:
136
+ context: ..
137
+ dockerfile: docker/Dockerfile.voice_screening
138
+ ports:
139
+ - "8502:8501" # Map host port 8502 to container port 8501
140
+ depends_on:
141
+ - db
142
+ - websocket_proxy
143
+ environment:
144
+ DATABASE_URL: postgresql://agentic_user:password123@db:5432/agentic_hr
145
+ PYTHONPATH: /app
146
+ WEBSOCKET_PROXY_URL: ws://websocket_proxy:8000/ws/realtime
147
+ BACKEND_API_URL: http://supervisor_api:8080
148
+ volumes:
149
+ # Mount local code for live updates
150
+ - ../:/app
151
+ command:
152
+ [
153
+ "streamlit",
154
+ "run",
155
+ "src/frontend/streamlit/voice_screening_ui/app.py",
156
+ "--server.port=8501",
157
+ "--server.address=0.0.0.0",
158
+ ]
159
+ networks:
160
+ - hrnet
161
+
162
+ # --- Supervisor Agent API ---
163
+ supervisor_api:
164
+ container_name: supervisor_api
165
+ build:
166
+ context: ..
167
+ dockerfile: docker/Dockerfile.supervisor_api
168
+ ports:
169
+ - "8080:8080" # Map host port 8080 to container port 8080
170
+ depends_on:
171
+ - db
172
+ environment:
173
+ # We set POSTGRES_HOST to 'db' so the agent connects to the container internal network
174
+ POSTGRES_HOST: ${POSTGRES_HOST}
175
+ POSTGRES_PORT: ${POSTGRES_PORT}
176
+ POSTGRES_USER: ${POSTGRES_USER}
177
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
178
+ POSTGRES_DB: ${POSTGRES_DB}
179
+ PYTHONPATH: /app
180
+ PROMPTLAYER_API_KEY: ${PROMPTLAYER_API_KEY}
181
+ OPENAI_API_KEY: ${OPENAI_API_KEY}
182
+ WEBSOCKET_PROXY_URL: ws://websocket_proxy:8000/ws/realtime
183
+ volumes:
184
+ # Mount local code for live updates
185
+ - ../:/app
186
+ command:
187
+ [
188
+ "uvicorn",
189
+ "src.api.app:app",
190
+ "--host",
191
+ "0.0.0.0",
192
+ "--port",
193
+ "8080",
194
+ "--reload",
195
+ ]
196
+ networks:
197
+ - hrnet
198
+
199
+ # --- Supervisor Agent UI ---
200
+ supervisor_ui:
201
+ container_name: supervisor_ui
202
+ build:
203
+ context: ..
204
+ dockerfile: docker/Dockerfile.supervisor
205
+ ports:
206
+ - "8503:8501" # Map host port 8503 to container port 8501
207
+ depends_on:
208
+ - db
209
+ - supervisor_api
210
+ environment:
211
+ # We set POSTGRES_HOST to 'db' so the agent connects to the container internal network
212
+ PYTHONPATH: /app
213
+ # API URL for the Streamlit UI to connect to
214
+ SUPERVISOR_API_URL: http://supervisor_api:8080/api/v1/supervisor
215
+ volumes:
216
+ # Mount local code for live updates
217
+ - ../:/app
218
+ command:
219
+ [
220
+ "streamlit",
221
+ "run",
222
+ "src/frontend/streamlit/supervisor_ui/app.py",
223
+ "--server.port=8501",
224
+ "--server.address=0.0.0.0",
225
+ ]
226
+ networks:
227
+ - hrnet
228
+
229
+ volumes:
230
+ postgres_data:
231
+ cvs_data:
232
+ driver: local
233
+
234
+ networks:
235
+ hrnet:
236
+ driver: bridge
docker/info.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## 🐳 Docker Services
2
+
3
+ ### Services and Ports
4
+
5
+ | Service | Description | Host Port | Container Port |
6
+ |---------|-------------|-----------|----------------|
7
+ | `db` | PostgreSQL 15 database with persistent storage | 5433 | 5432 |
8
+ | `candidates_db_init` | Python backend container — initializes DB schema | N/A | N/A |
9
+ | `cv_upload_streamlit` | Streamlit app for CV uploads | 8501 | 8501 |
10
+ | `websocket_proxy` | WebSocket proxy for OpenAI Realtime API | 8000 | 8000 |
11
+ | `voice_screening_ui` | Streamlit app for voice screening | 8502 | 8501 |
12
+ | `supervisor_ui` | Streamlit app for Supervisor Agent | 8503 | 8501 |
13
+ | `supervisor_api` | FastAPI backend for Supervisor Agent | 8080 | 8080 |
14
+
15
+ ---
16
+
17
+ ### Run Command
18
+
19
+ ```bash
20
+ docker compose --env-file .env -f docker/docker-compose.yml up --build
21
+ ```
22
+
23
+ ---
24
+
25
+ ### Resetting the Environment
26
+
27
+ When making structural changes to the database (e.g., modifying models, updating Enums) or when you simply want a clean slate for testing, the persistent Docker volumes may cause conflicts with new code.
28
+
29
+ To completely reset the environment and database:
30
+
31
+ ```bash
32
+ # 1. Stop running containers
33
+ docker compose -f docker/docker-compose.yml down
34
+
35
+ # 2. Remove the persistent database volume
36
+ docker volume rm docker_postgres_data
37
+
38
+ # 3. Rebuild and start fresh
39
+ docker compose --env-file .env -f docker/docker-compose.yml up --build
40
+ ```
docs/agents/agent_ochestrator.md ADDED
File without changes
docs/agents/cv_screening.md ADDED
File without changes
docs/agents/google_mcp_agent.md ADDED
File without changes
docs/agents/judging_agent.md ADDED
File without changes
docs/agents/supervisor/mvps/mvp1/mvp_v1.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Owens
docs/agents/supervisor/mvps/mvp2/mvp_v2.md ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ***MVP version #2***
2
+ ---
3
+
4
+
5
+ ## HR-Triggered Autonomous Workflow Concept
6
+
7
+ The system is designed to operate **autonomously** while still allowing HR to initiate workflows and request status insights.
8
+ This ensures maximum automation without losing control or clarity in the process.
9
+
10
+ ---
11
+
12
+ ### **HR Interaction Trigger**
13
+
14
+ When HR opens the UI, they can interact with the supervisor agent by asking questions such as:
15
+
16
+ > **“Hey recruitment agent, what is the current status quo? Any new applicants? How many have passed CV screening?”**
17
+
18
+ The supervisor agent then:
19
+
20
+ 1. Queries the database using predefined tools
21
+ 2. Generates a clear, human-friendly status report
22
+ 3. Waits for HR instructions on how to proceed
23
+
24
+ HR can then issue high-level commands like:
25
+
26
+ - **“Process all new applicants.”**
27
+ - **“Do not process new applicants further — notify them instead.”**
28
+ - **“Continue processing only applicants who already passed screening.”**
29
+
30
+ ---
31
+
32
+ ### **Supervisor Executes Fully Autonomous Actions**
33
+
34
+ Once HR gives the high-level command, the supervisor performs all actions autonomously:
35
+
36
+ - **Process new applicants**
37
+ - Parse CVs
38
+ - Run CV screening
39
+ - Update DB
40
+ - Notify or proceed depending on results
41
+
42
+ - **Process screened applicants further**
43
+ - Notify candidate
44
+ - Request available time slots
45
+ - Match HR availability
46
+ - Schedule interview
47
+ - Send confirmation emails
48
+
49
+ ---
50
+
51
+ ### **Concurrency and Isolation**
52
+
53
+ To avoid mixing contexts across candidates:
54
+
55
+ - **Only one supervisor agent instance runs at a time**
56
+ - Supervisor processes candidates **sequentially**
57
+ - Each candidate is handled **individually and deterministically**
58
+
59
+ This avoids:
60
+ - Context bleed
61
+ - Duplicate actions
62
+ - Race conditions
63
+ - Mixed reasoning across candidates
64
+
65
+ ---
66
+
67
+ ### **Per-Candidate Deterministic State Machine**
68
+
69
+ Each candidate has a small state object:
70
+
71
+ ```json
72
+ {
73
+ "candidate_id": 123,
74
+ "state": "cv_uploaded",
75
+ "checklist_path": "users/123/checklist.md"
76
+ }
77
+ ```
78
+ This keeps the workflow predictable, restartable, and isolated.
79
+
80
+ ---
81
+
82
+ ### ***Per-Candidate Checklist File***
83
+ Each candidate has a personal Markdown checklist:
84
+ ```text
85
+ # Candidate Checklist — ID 123
86
+
87
+ - [x] CV uploaded
88
+ - [x] CV parsed and stored
89
+ - [x] CV screening started
90
+ - [x] CV screening completed
91
+ - [ ] Screening results notified to candidate
92
+ - [ ] Asked candidate for available time slots
93
+ - [ ] Received candidate availability
94
+ - [ ] Checked HR availability
95
+ - [ ] Scheduled interview
96
+ - [ ] Final confirmation email sent
97
+ ```
98
+ The supervisor uses this checklist to determine the next atomic action.
99
+ It loads only this candidate’s context, performs exactly one update, writes back, and moves on.
100
+
101
+ ---
102
+ ## **Hybrid Progress Tracking — DB Status + Checklist**
103
+
104
+ The HR agent maintains two synchronized layers of workflow state:
105
+
106
+ - **Database `status` field:**
107
+ Captures the **coarse-grained milestone** in the candidate’s lifecycle
108
+ (e.g., `applied`, `cv_screened`, `interview_scheduled`, `decision_made`).
109
+ → This is the **authoritative system state** used for HR dashboards, analytics, and reporting.
110
+
111
+ - **Per-candidate Markdown checklist:**
112
+ Tracks **fine-grained atomic actions** that occur within each milestone
113
+ (e.g., CV parsed, CV screened, email sent, candidate replied).
114
+ → This serves as the **agent’s operational log**, enabling deterministic reasoning, auditing, and safe restarts.
115
+
116
+ ---
117
+
118
+ ### **Checklist and Milestone Boundaries**
119
+
120
+ The **checklist** is composed of multiple **substeps**, each representing one small, deterministic action.
121
+ When all substeps belonging to a stage are completed, the system reaches a **milestone boundary**.
122
+ That boundary marks a safe point to update the candidate’s `status` field in the database.
123
+
124
+ | Milestone (`status` in DB) | Meaning | Checklist Substeps Leading to Boundary |
125
+ |-----------------------------|----------|---------------------------------------|
126
+ | `applied` | Candidate record created | `[x] CV uploaded`, `[x] CV parsed` |
127
+ | `cv_screened` | Screening phase finished | `[x] Screening started`, `[x] Screening completed`, `[x] Result stored` |
128
+ | `interview_scheduled` | Interview arranged | `[x] Candidate notified`, `[x] Availability received`, `[x] Interview scheduled` |
129
+ | `decision_made` | Final decision delivered | `[x] Interview completed`, `[x] Decision logged`, `[x] Notification email sent` |
130
+
131
+ ---
132
+
133
+ ### **Sync Rule**
134
+
135
+ 1. After **each atomic substep**, the supervisor updates the checklist file.
136
+ 2. When a **milestone boundary** is reached (all substeps for a phase checked off),
137
+ the supervisor updates the corresponding `status` field in the database.
138
+ 3. The checklist remains the **fine-grained operational truth**,
139
+ while the database holds the **coarse-grained canonical truth**.
140
+
141
+ ---
142
+
143
+ ### **Summary**
144
+
145
+ - **Checklist = micro-level progress tracker** (agent reasoning + recovery)
146
+ - **Milestone boundaries = transition triggers** (define when to sync with DB)
147
+ - **Database `status` = macro-level lifecycle state** (system-wide reference)
148
+
149
+ This hybrid approach combines **LLM-friendly transparency** with **system-level consistency**, ensuring the agent can reason, recover, and scale safely.
150
+
151
+
152
+ ---
153
+
154
+ ### ***Result***
155
+ This approach provides:
156
+ - High autonomy
157
+ - Strong safety boundaries
158
+ - No context mixing
159
+ - Clear state tracking
160
+ - Reliable execution
161
+ - HR keeps high-level control
162
+ - LLM handles reasoning, routing, and next steps autonomously
163
+ This structure is scalable, maintainable, and production-friendly while still pushing agent autonomy very far.
164
+
165
+
166
+ ## ⚡ ***Handling Everything Concurrently — The Async Supervisor Layer***
167
+ ---
168
+ `The system must support concurrent processing of multiple candidate groups, each representing a different stage in the application pipeline (e.g., CV screening, voice screening, decision). Within each group, it should be able to process batches of candidates simultaneously while preserving per-candidate isolation and state consistency.`
169
+
170
+ ### **Thread-Based Per-Candidate Isolation For the Rescue**
171
+
172
+ To ensure deterministic, fault-tolerant, and concurrent execution, the system leverages **LangGraph thread IDs** for per-candidate isolation:
173
+
174
+ 1. **Supervisor Delegation**
175
+ The Supervisor Agent queries all candidates, groups them by their current `status` (e.g., CV screening, voice screening, decision), and passes the **list of candidate IDs** to the appropriate subagent tool.
176
+ Each subagent handles its own data loading, ensuring the Supervisor remains lightweight and purely orchestration-focused.
177
+
178
+ 2. **Subagent Execution (Thread-per-Candidate)**
179
+ Inside each subagent (e.g., `screen_cv`), the system iterates over all received candidate IDs.
180
+ For each candidate:
181
+ - The **candidate ID serves as the `thread_id`**, providing a unique persistent context in LangGraph.
182
+ - The subagent loads candidate data from the database (CV path, JD path, etc.).
183
+ - The CV or voice screening logic runs **within that thread’s context**.
184
+ - On completion, the results are written back to the database, and the per-candidate checklist and state are updated.
185
+
186
+ 3. **Parallel and Safe Processing**
187
+ Subagents can process multiple candidates concurrently by spawning asynchronous executions per `thread_id`.
188
+ Each candidate’s context remains isolated, preventing race conditions or context mixing.
189
+
190
+ **Result:**
191
+ - Supervisor coordinates and dispatches candidate groups
192
+ - Subagents handle per-candidate logic using thread-based persistence
193
+ - Each candidate’s run is self-contained, recoverable, and writes its final results back to the database
194
+
195
+ > **Note:**
196
+ > During a “Process All” operation, the Supervisor Agent executes **multiple reasoning loops**, invoking each subagent tool in sequence (e.g., `screen_cv`, `voice_screening`, `schedule_hr_interview`).
197
+ > After each tool call, it observes the result, reasons about the next step, and continues until all candidate groups are processed.
198
+
199
+
200
+
201
+ Latest chat: https://chatgpt.com/share/6920d318-3f64-8012-8fca-b17316093131
202
+
203
+ ---
204
+
205
+ > below mst be adapted based on section above:
206
+
207
+ ...
208
+ ```mermaid
209
+ flowchart TD
210
+
211
+ HR_UI[UI: HR opens dashboard<br/>and requests candidate status]
212
+ --> REPORT[System returns report<br/>showing new and screened candidates]
213
+
214
+ REPORT --> PARALLEL[Async Supervisor<br/>launches concurrent group tasks]
215
+
216
+ %% --- New candidate path ---
217
+ PARALLEL --> NEW_FLOW[Process new candidates<br/>CV screening pipeline]
218
+ NEW_FLOW --> A[Delegate screening to subagent]
219
+ A --> B[Subagent screens CV]
220
+ B --> C[Write screening results to DB]
221
+ C --> D[Supervisor receives results]
222
+ D --> E{Did candidate pass screening?}
223
+ E -- No --> REJECT[Notify candidate and HR<br/>application rejected]
224
+ E -- Yes --> PASSED[Notify candidate and HR<br/>passed screening]
225
+
226
+ %% --- Screened candidate path ---
227
+ PARALLEL --> SCREENED_FLOW[Process screened candidates<br/>interview scheduling pipeline]
228
+ SCREENED_FLOW --> I[Request candidate time slots]
229
+ I --> J[Check HR calendar availability]
230
+ J --> K[Schedule interview]
231
+ K --> L[Notify HR and candidate<br/>interview confirmed]
232
+
233
+
234
+
235
+ ```
236
+
237
+ To support concurrent processing across groups and candidates, the supervisor now operates as an asynchronous orchestrator.
238
+ It remains a single agent context — responsible for reasoning, reporting, and orchestration — but leverages asyncio to execute multiple workflows concurrently.
239
+ This allows the system to:
240
+ - Process multiple groups (e.g., new vs. screened candidates) in parallel
241
+ - Process multiple candidates per group concurrently
242
+ - Maintain isolation and determinism per candidate through separate state/checklist files
243
+
244
+ ---
245
+
246
+ Conceptual Overview
247
+ 1. HR issues a high-level command (e.g., “Process all candidates”).
248
+ 2. The supervisor queries the database and identifies candidate groups.
249
+ 3. It launches async tasks for each group simultaneously.
250
+ 4. Within each group, candidates are processed concurrently — each running the deterministic checklist logic described above.
251
+ 5. The supervisor awaits completion of all group tasks and reports progress and results.
252
+
253
+ This preserves:
254
+ - ✅ Single supervisor reasoning context
255
+ - ✅ Concurrent group + per-candidate execution
256
+ - ✅ Isolated per-candidate state and file I/O
257
+ - ✅ High throughput without context bleed
258
+
259
+ ---
260
+
261
+ ***Conceptual Async Code Example***
262
+
263
+ ```python
264
+ import asyncio
265
+ from typing import List
266
+
267
+ # --- Candidate-level deterministic flow ---
268
+ async def process_candidate(candidate):
269
+ """Execute the per-candidate checklist and state transitions."""
270
+ state = await load_candidate_state(candidate.id)
271
+
272
+ if state == "cv_uploaded":
273
+ await parse_and_screen_cv(candidate)
274
+ elif state == "screened":
275
+ await schedule_interview(candidate)
276
+ # ... additional states here
277
+
278
+ await save_candidate_state(candidate.id, state)
279
+ print(f"✅ Candidate {candidate.id} processed ({state})")
280
+
281
+
282
+ # --- Group-level concurrent handler ---
283
+ async def process_group(candidates: List, group_name: str):
284
+ """Handle all candidates in one group concurrently."""
285
+ print(f"⚙️ Processing group: {group_name} ({len(candidates)} candidates)")
286
+ tasks = [process_candidate(c) for c in candidates]
287
+ await asyncio.gather(*tasks)
288
+ print(f"✅ Group {group_name} completed")
289
+
290
+
291
+ # --- Main supervisor orchestration ---
292
+ async def supervisor_run():
293
+ """Supervisor orchestrates all concurrent candidate workflows."""
294
+ print("🧠 Supervisor initialized")
295
+
296
+ # Query database and classify candidates
297
+ report = await get_candidate_report()
298
+ new_candidates = report["new"]
299
+ screened_candidates = report["screened"]
300
+
301
+ # Launch group workflows concurrently
302
+ await asyncio.gather(
303
+ process_group(new_candidates, "new_candidates"),
304
+ process_group(screened_candidates, "screened_candidates")
305
+ )
306
+
307
+ print("🎯 All candidate groups processed successfully")
308
+
309
+
310
+ # --- Entry point ---
311
+ if __name__ == "__main__":
312
+ asyncio.run(supervisor_run())
313
+ ```
314
+
315
+ ---
316
+ ***Key Properties***
317
+ - **Async orchestration, single agent:** The supervisor coordinates all tasks without duplicating reasoning contexts.
318
+ - **Per-candidate determinism:** Each checklist/state file is loaded, updated, and written atomically.
319
+ - **Parallel group execution:** New and screened candidates can be processed simultaneously.
320
+ - **Scalability path:** The same async structure can later integrate with LangGraph’s parallel nodes or distributed queues.
docs/agents/supervisor/mvps/mvp2/single_candidate_mvp.md ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # ***Single-Candidate MVP — Tick Box Milestones***
3
+ ---
4
+
5
+ This V1 map outlines the simplest complete workflow for the HR agent system: HR enters the UI, receives a clear overview of all candidates and their screening status, and then chooses one of two actions—process new applicants or continue with those who are already screened. The supervisor then carries out the chosen workflow step-by-step, invoking the appropriate subagents (screening, Gmail, calendar) and updating each candidate’s state accordingly.
6
+
7
+
8
+ ## **V2 Workflow Diagram — HR → Supervisor → Actions**
9
+ ```mermaid
10
+ flowchart TD
11
+
12
+ HR[HR opens UI] --> Q[Supervisor generates status report: applicants, screened, passed, failed]
13
+
14
+ Q --> HR_Decision{HR chooses action}
15
+
16
+ HR_Decision --> A[Option A: Process new applicant]
17
+ HR_Decision --> B[Option B: Process screened applicant]
18
+
19
+ %% Option A path
20
+ A --> A1[Supervisor triggers screening]
21
+ A1 --> A2[Subagent screens candidate]
22
+ A2 --> A3[Screening result stored in DB]
23
+ A3 --> A4[Candidate status updated]
24
+
25
+ %% Option B path
26
+ B --> B_DECISION{Candidate accepted or declined?}
27
+
28
+ B_DECISION --> B1A[If accepted: Gmail + Calendar workflow]
29
+ B_DECISION --> B1B[If declined: Gmail rejection email]
30
+
31
+ %% End nodes
32
+ A4 --> END((Done))
33
+ B1A --> END
34
+ B1B --> END
35
+
36
+ ```
37
+
38
+ # Single-Candidate MVP — General Tick Box Milestones
39
+
40
+ ## **1) CV Upload + Candidate Storage**
41
+ - [ ] Candidate record created in DB (manual trigger OK)
42
+ - [ ] CV file uploaded (manual OK for MVP)
43
+ - [ ] CV parsed into structured format
44
+ - [ ] Parsed CV stored in DB linked to candidate
45
+ - [ ] Candidate status set to `uploaded`
46
+
47
+ ---
48
+
49
+ ## **2) Supervisor + Basic UI (Single Entry Point)**
50
+
51
+ ### **2.1 HR Status Query & Reporting**
52
+ - [ ] Supervisor responds to: “What is the current status quo?”
53
+ - [ ] Supervisor reports total number of applicants
54
+ - [ ] Supervisor reports how many have been screened
55
+ - [ ] Supervisor reports how many passed vs failed screening
56
+ - [ ] Supervisor presents results as a clear HR-friendly summary report
57
+
58
+ ### **2.2 Supervisor Actions**
59
+ - [ ] “Process new applicant” option available
60
+ - [ ] “Process screened applicant” option available
61
+
62
+ ### **2.3 Action Logic**
63
+ - [ ] Choosing “process new applicant” triggers initial screening workflow
64
+ - [ ] Choosing “process screened applicant” triggers:
65
+ - [ ] Gmail + calendar workflow for accepted candidates
66
+ - [ ] Gmail rejection workflow for declined candidates
67
+
68
+ ### **2.4 State Updates**
69
+ - [ ] Supervisor updates candidate status after each action
70
+ - [ ] Supervisor logs each action outcome into DB
71
+
72
+ ---
73
+
74
+ ## **3) CV Screening Subagent**
75
+ - [ ] Subagent loads candidate record
76
+ - [ ] Subagent loads stored CV text
77
+ - [ ] Subagent performs CV screening
78
+ - [ ] Structured screening result saved to DB
79
+ - [ ] Candidate status updated to `screened`
80
+ - [ ] Supervisor UI reflects updated screening status
81
+
82
+ ---
83
+
84
+ ## **4) Per-Candidate Deterministic State Machine**
85
+ - [ ] Each candidate has a dedicated state object (e.g., `state: "cv_uploaded"`)
86
+ - [ ] State object persisted in DB or file
87
+ - [ ] Supervisor reads this state before taking actions
88
+ - [ ] Supervisor updates the state after actions
89
+ - [ ] Workflow remains predictable and restartable per candidate
90
+ - [ ] Each candidate’s context is isolated (no cross-candidate bleed)
91
+
92
+ ---
93
+
94
+ ## **5) Per-Candidate Checklist File**
95
+ - [ ] A Markdown checklist file is created per candidate
96
+ - [ ] Checklist is updated at each atomic step
97
+ - [ ] Supervisor loads checklist to determine next required action
98
+ - [ ] Checklist mirrors real workflow steps (upload → screening → notification → scheduling)
99
+ - [ ] Checklist allows deterministic progress tracking
100
+ - [ ] Checklist helps ensure one atomic action per supervisor step
101
+
102
+
103
+
104
+ ---
105
+
106
+
107
+ # 🧭 Incremental Implementation Roadmap — From Skeleton to MVP
108
+
109
+ This roadmap breaks the HR Agent MVP into incremental, testable phases.
110
+ Each phase builds on the previous one — keeping the system functional at every step while increasing autonomy, determinism, and traceability.
111
+
112
+ A key invariant across all phases:
113
+ > 🧩 **Each atomic action must update the per-candidate Markdown checklist**
114
+ > The checklist is the single source of truth for progress, state recovery, and auditability.
115
+
116
+ ***Checklist:***
117
+ ```text
118
+ # Candidate Checklist — ID 123
119
+
120
+ - [ ] CV uploaded, parsed and stored
121
+ - [ ] CV screening (pass / fail)
122
+ - [ ] Screening results notified to candidate & HR
123
+ - [ ] Asked candidate for available time slots
124
+ - [ ] Received candidate availability
125
+ - [ ] Checked HR availability
126
+ - [ ] Scheduled interview
127
+ - [ ] Final confirmation email sent
128
+ ```
129
+ ---
130
+
131
+ ## **Phase 1 — Foundation Layer: Candidate I/O + Static State**
132
+
133
+ Goal: Establish basic data persistence and candidate representation.
134
+ Outcome: You can manually create a candidate, attach a CV, and store structured data.
135
+
136
+ - [ ] DB schema or JSON store for candidates
137
+ - `candidate_id`, `name`, `cv_path`, `state`, `screening_result`
138
+ - [ ] Manual script or simple UI form to create a candidate
139
+ - [ ] Upload CV file (manual or API endpoint)
140
+ - [ ] Parse CV into structured format
141
+ - [ ] Store parsed CV in DB
142
+ - [ ] Candidate state set to `"cv_uploaded"`
143
+ - [ ] ✅ **Checklist updated after each atomic step:**
144
+ - `[x] CV uploaded`
145
+ - `[x] CV parsed`
146
+ - `[x] Candidate stored`
147
+
148
+ ---
149
+
150
+ ## **Phase 2 — Supervisor Core Logic (CLI or Barebones UI)**
151
+
152
+ Goal: Implement the supervisor agent’s reasoning + reporting loop for one candidate.
153
+ Outcome: HR can ask status questions and issue simple actions.
154
+
155
+ - [ ] Simple command interface or Streamlit-like dashboard
156
+ - [ ] Supervisor responds to: “What’s the current status quo?”
157
+ - [ ] Supervisor reports:
158
+ - [ ] Total number of applicants
159
+ - [ ] Number screened
160
+ - [ ] Number passed vs failed
161
+ - [ ] HR can issue commands:
162
+ - [ ] `process_new_applicant`
163
+ - [ ] `process_screened_applicant`
164
+ - [ ] Supervisor executes one step → updates candidate state
165
+ - [ ] State transitions logged
166
+ - [ ] ✅ **Checklist updated automatically after each supervisor action**
167
+
168
+ ---
169
+
170
+ ## **Phase 3 — Screening Subagent Integration**
171
+
172
+ Goal: Automate CV evaluation and store results.
173
+ Outcome: Supervisor delegates screening to subagent and records outcome.
174
+
175
+ - [ ] Subagent loads candidate record + parsed CV
176
+ - [ ] Runs screening model (mock or real)
177
+ - [ ] Produces structured result (e.g., `{passed: True, score: 85}`)
178
+ - [ ] Saves result in DB
179
+ - [ ] Candidate state transitions:
180
+ - `"cv_uploaded"` → `"screened_passed"` or `"screened_failed"`
181
+ - [ ] Supervisor report reflects updated screening counts
182
+ - [ ] ✅ **Checklist updated:**
183
+ - `[x] Screening started`
184
+ - `[x] Screening completed`
185
+ - `[x] Result stored`
186
+
187
+ ---
188
+
189
+ ## **Phase 4 — Candidate Communication Layer (Gmail Integration)**
190
+
191
+ Goal: Automate candidate notifications based on screening results.
192
+ Outcome: Supervisor triggers Gmail subagent to send emails.
193
+
194
+ - [ ] Gmail subagent setup
195
+ - [ ] For `screened_failed`: send rejection email
196
+ - [ ] For `screened_passed`: send congratulations + request time slots
197
+ - [ ] Email status stored in DB
198
+ - [ ] Candidate state transitions:
199
+ - `"screened_failed"` → `"notified_rejection"`
200
+ - `"screened_passed"` → `"awaiting_time_slots"`
201
+ - [ ] ✅ **Checklist updated:**
202
+ - `[x] Candidate notified of result`
203
+ - `[x] Email status recorded`
204
+
205
+ ---
206
+
207
+ ## **Phase 5 — Interview Scheduling Layer (Calendar Integration)**
208
+
209
+ Goal: Automate scheduling for passed candidates.
210
+ Outcome: Supervisor matches availability and books meetings.
211
+
212
+ - [ ] Calendar subagent setup
213
+ - [ ] Candidate time slot parsing (from email reply or mock)
214
+ - [ ] Check HR calendar availability
215
+ - [ ] Schedule meeting and send confirmation email
216
+ - [ ] Candidate state transitions:
217
+ - `"awaiting_time_slots"` → `"interview_scheduled"`
218
+ - [ ] ✅ **Checklist updated:**
219
+ - `[x] Candidate provided time slots`
220
+ - `[x] HR availability checked`
221
+ - `[x] Interview scheduled`
222
+ - `[x] Confirmation sent`
223
+
224
+ ---
225
+
226
+ # Advanced System Features - Future Directions for Next MVP
227
+
228
+ ## **Phase 6 — Determinism + Persistence Layer**
229
+
230
+ Goal: Make the system predictable, restartable, and auditable.
231
+ Outcome: Each candidate runs in isolation with explicit state and checklist.
232
+
233
+ - [ ] Per-candidate state object stored in DB or JSON
234
+ - [ ] Per-candidate Markdown checklist file created:
235
+
236
+
237
+ ## **Phase 7 — Async Supervisor Orchestration (Scaling Up)**
238
+
239
+ Goal: Extend single-candidate flow to multiple candidates concurrently.
240
+ Outcome: Async orchestration across candidate groups.
241
+
242
+ - [ ] Async supervisor runs concurrently across groups:
243
+ - [ ] New candidates → screening path
244
+ - [ ] Screened candidates → scheduling path
245
+ - [ ] Each candidate processed in an isolated coroutine
246
+ - [ ] Checklist + state ensure deterministic behavior per candidate
247
+ - [ ] Supervisor reports real-time progress
248
+ - [ ] Single reasoning context preserved
249
+ - [ ] ✅ **Each candidate’s checklist still governs progression, ensuring isolation and safe concurrency**
250
+ - [ ] Supervisor awaits all async tasks and compiles final HR summary report
251
+ - [ ] System supports safe restarts (resume from last known checklist state)
252
+ - [ ] Scalable to LangGraph or distributed queue orchestration later on
253
+
254
+ This roadmap breaks the HR Agent MVP into incremental, testable phases.
255
+ Each phase builds logically on the previous one — so the system remains functional at every step while increasing in autonomy and complexity.
256
+
257
+ ---
docs/agents/supervisor/mvps/mvp2/tools_needed.md ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ⚙️ Tools Required for MVP (Phases 1–5)
2
+
3
+ The system consists of a **Supervisor Agent** (central orchestrator) and several **specialized subagents**.
4
+ Each tool corresponds to a specific capability needed for the single-candidate MVP flow — from CV upload to interview scheduling.
5
+
6
+ ---
7
+
8
+ ## 🧠 **Supervisor Agent (Core Orchestrator)**
9
+
10
+ ### **Role**
11
+ Acts as the **central controller**:
12
+ - Interfaces with HR (via UI or chat)
13
+ - Handles reasoning, status reporting, and command interpretation
14
+ - Orchestrates subagents (screening, Gmail, calendar)
15
+ - Updates both the database and checklist after each atomic action
16
+
17
+ ### **Tools Required**
18
+
19
+ | Tool | Purpose | Used in Phase |
20
+ |------|----------|---------------|
21
+ | 🗃️ **Database Tool / ORM Adapter** | Read, create, and update `Candidate` records (status, CV paths, results). | 1–5 |
22
+ | 📄 **File I/O Tool** | Read/write per-candidate checklist and parsed CV files. | 1–5 |
23
+ | 📊 **Reporting Helper / Aggregation Utility** | Query DB and summarize candidate counts (new, screened, passed, failed). | 2 |
24
+ | 🧩 **Subagent Dispatch Interface** | Send structured tasks to subagents (screening, Gmail, calendar). | 3–5 |
25
+ | 🧱 **State Manager** | Load and update candidate’s deterministic state object (`state`, `checklist`, `status`). | 4–5 |
26
+ | 🕵️ **HR Command Parser / Intent Handler** | Interpret HR’s natural-language instructions (e.g., “process new applicants”). | 2 |
27
+
28
+ ---
29
+
30
+ ## 🤖 **Subagents & Their Tools**
31
+
32
+ ### **1. CV Screening Subagent**
33
+ **Phase:** 3
34
+ **Purpose:** Automatically screen and score CVs.
35
+
36
+ | Tool | Purpose |
37
+ |------|----------|
38
+ | 📄 **CV Parser** | Extract structured text from uploaded CV (PDF/DOCX). |
39
+ | 🧮 **Screening Model / Classifier** | Evaluate parsed CV using rules or an ML/LLM-based model. |
40
+ | 🗃️ **DB Access Tool** | Save screening results and update `Candidate.status = cv_screened`. |
41
+ | 📄 **Checklist Writer** | Mark `[x] Screening started` and `[x] Screening completed` in the checklist. |
42
+
43
+ ---
44
+
45
+ ### **2. Gmail Subagent**
46
+ **Phase:** 4
47
+ **Purpose:** Send automated emails to candidates based on screening results.
48
+
49
+ | Tool | Purpose |
50
+ |------|----------|
51
+ | 📬 **Gmail API Wrapper** | Send templated emails (rejection or invitation). |
52
+ | 🧠 **Template Manager** | Store and select appropriate email templates. |
53
+ | 🗃️ **DB Access Tool** | Record email activity and update candidate state. |
54
+ | 📄 **Checklist Writer** | Mark `[x] Candidate notified` and `[x] Email status recorded`. |
55
+
56
+ ---
57
+
58
+ ### **3. Calendar / Scheduling Subagent**
59
+ **Phase:** 5
60
+ **Purpose:** Automate interview scheduling for passed candidates.
61
+
62
+ | Tool | Purpose |
63
+ |------|----------|
64
+ | 🗓️ **Google Calendar API Wrapper** | Retrieve HR availability and create interview events. |
65
+ | 📬 **Gmail API (reuse)** | Send scheduling confirmations and time slot requests. |
66
+ | 🧠 **Availability Matcher** | Compare candidate-provided slots vs HR calendar availability. |
67
+ | 🗃️ **DB Access Tool** | Update `Candidate.status = interview_scheduled`. |
68
+ | 📄 **Checklist Writer** | Mark `[x] HR availability checked`, `[x] Interview scheduled`, `[x] Confirmation sent`. |
69
+
70
+ ---
71
+
72
+ ## 🧾 **Cross-Cutting Utilities (Shared by All Agents)**
73
+
74
+ | Utility | Purpose | Used by |
75
+ |----------|----------|----------|
76
+ | 🧩 **Checklist Manager** | CRUD operations on per-candidate Markdown checklist files (load, mark, persist). | All |
77
+ | 🧱 **State Sync Layer** | Sync checklist milestone boundaries with DB `status` updates. | Supervisor |
78
+ | ⏱️ **Logging & Audit Utility** | Record all actions, errors, and state transitions. | All |
79
+ | 🧮 **Config / Environment Loader** | Manage API keys, paths, and credentials for Gmail & Calendar. | All networked agents |
80
+
81
+ ---
82
+
83
+ ## 🧭 **Tool Overview by Phase**
84
+
85
+ | Phase | Supervisor Tools | Subagents / Tools |
86
+ |-------|-------------------|------------------|
87
+ | **1 — Candidate I/O + Storage** | DB Adapter, File I/O, Checklist Manager | CV Parser (manual for MVP) |
88
+ | **2 — Supervisor + UI** | HR Command Parser, DB Reporter, Checklist Manager | — |
89
+ | **3 — CV Screening** | Subagent Dispatcher, Checklist Manager | CV Parser, Screening Model, DB Writer |
90
+ | **4 — Candidate Communication** | Subagent Dispatcher, Checklist Manager | Gmail API, Template Manager |
91
+ | **5 — Interview Scheduling** | Subagent Dispatcher, Checklist Manager | Calendar API, Availability Matcher, Gmail API |
92
+
93
+ ---
94
+
95
+ ## ✅ **Summary**
96
+
97
+ - **Supervisor Agent Tools:**
98
+ - DB Adapter
99
+ - Checklist Manager
100
+ - HR Interface (UI or CLI)
101
+ - Subagent Dispatcher
102
+ - State Sync Logic
103
+
104
+ - **Subagents:**
105
+ - **Screening Subagent:** CV Parser + Screening Model
106
+ - **Gmail Subagent:** Email Templating + Send API
107
+ - **Calendar Subagent:** Scheduling + Availability Matching
108
+
109
+ Together, these tools form the complete single-candidate MVP pipeline —
110
+ from candidate intake → CV screening → communication → interview scheduling.
docs/agents/supervisor/mvps/overview.md ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # **Application Flow**
2
+
3
+ ## **MVP Version #2**
4
+
5
+
6
+ ```mermaid
7
+ flowchart TD
8
+
9
+ A[CV Upload] --> B[Store & Parse CV]
10
+
11
+ B --> C[Trigger: CV Screening]
12
+
13
+ C --> D[Supervisor Delegates<br/>Screening to Subagent]
14
+
15
+ D --> E[Write Results to DB]
16
+
17
+ E --> F[Supervisor Receives Screening Results]
18
+
19
+ F --> G{Did Candidate Pass<br/>CV Screening?}
20
+
21
+ G -- No --> H[Notify Candidate & HR:<br/>Application Rejected]
22
+
23
+ G -- Yes --> I[Notify Candidate & HR:<br/>Passed Screening]
24
+
25
+ I --> J[Request Candidate's<br/>Available Time Slots]
26
+
27
+ J --> K[Check HR Calendar<br/>Availability]
28
+
29
+ K --> L[Schedule Person-Person<br/>Interview]
30
+
31
+ L --> M[Notify HR & Candidate<br/>Interview Confirmed]
32
+ ```
33
+
34
+ The first goal is to ensure the application flows and works autonomously as follows:
35
+
36
+ ### **1) CV Submission**
37
+ - Applicant submits CV
38
+ - CV is parsed and stored
39
+
40
+ ### **2) CV Screening**
41
+ - Supervisor agent becomes aware that a CV was uploaded
42
+ - A **“CV was uploaded” signal** triggers the supervisor to delegate **CV screening** to a sub-agent
43
+ - Results are written to the database & candidate status is updated
44
+ - A **“CV was screened” signal** notifies the supervisor that results are available and is able to read the results from db
45
+
46
+ ### **3) Success / Failure Notification**
47
+
48
+ Based on CV screening results that the supervisor injected into its context, it decides:
49
+
50
+ #### **a) Not Passed**
51
+ - Trigger sub-agent to notify candidate *and* HR via email that the candidate did not meet requirements
52
+
53
+ #### **b) Passed**
54
+ - Trigger sub-agent to:
55
+ - Notify candidate and HR of the successful CV screening
56
+ - Ask candidate to provide several available time slots
57
+ - Check HR’s available time slots in their calendar
58
+ - Schedule a meeting based on overlapping availability
59
+ - Notify HR that candidate X passed CV screening and that an interview was scheduled on **`dd-mm-yyyy`**
60
+
61
+
62
+
63
+ ## **Final**
64
+ *(To be defined)*
docs/agents/supervisor/supervisor_general.md ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Supervisor Agent Overview
2
+ This document explains the role, behavior, and context-engineering strategy of the Supervisor Agent used in the agentic HR recruitment system. It describes how the supervisor plans, coordinates, delegates, and adapts the multi-agent workflow, and how context is compressed, summarized, and managed to maintain robustness across long-running interactions.
3
+
4
+ It also explains context-engineering strategies that are utilized in order to reduce token usage along with increasing reliability and task completion rate of the agents.
5
+
6
+ ---
7
+
8
+ ## 1. Purpose of the Supervisor Agent
9
+ The Supervisor Agent serves as the centralized orchestrator responsible for maintaining global workflow control. Its role is to ensure that each subagent operates in the correct order, under the correct conditions, with the right context, and with full visibility into progress and failures.
10
+
11
+ At a high level, the supervisor is responsible for:
12
+ - Generating and maintaining the end-to-end hiring plan.
13
+ - Determining which subagent should execute next.
14
+ - Providing stateful context to each subagent.
15
+ - Performing adaptive re-planning when outputs or conditions change.
16
+ - Managing memory summaries and preventing context pollution.
17
+ - Producing explainable logs and reasoning traces for the dashboard.
18
+
19
+ This agent ensures that the entire HR pipeline behaves autonomously while remaining transparent, safe, and resilient.
20
+
21
+ ---
22
+
23
+ ## 2. High-Level Workflow
24
+ The supervisor follows a structured, plan-driven execution model. The default plan is:
25
+
26
+ 1. CV Screening
27
+ 2. Voice Screening
28
+ 3. HR Interview Scheduling
29
+ 4. Final Decision Report
30
+
31
+ However, execution is not strictly linear. The supervisor can skip, re-order, repeat, or halt steps based on subagent outputs.
32
+
33
+ ### Workflow Model
34
+ 1. **Initialize Plan**
35
+ - Build an initial sequence of workflow stages based on available candidate data.
36
+ - Load any relevant memory summaries or past runs from the database.
37
+
38
+ 2. **Select Next Stage**
39
+ - Evaluate current state.
40
+ - Choose the next subagent based on plan progress and real-time results.
41
+
42
+ 3. **Construct Subagent Context Package**
43
+ - Provide the subagent with the minimal context they need:
44
+ - Candidate details
45
+ - Results from prior stages
46
+ - Relevant memory summaries
47
+ - Tool call history (when helpful)
48
+ - Current workflow goal
49
+
50
+ 4. **Invoke the Subagent**
51
+ - The selected agent executes a task using LangGraph tool calls or MCP integrations.
52
+ - Outputs are validated and stored in state and database.
53
+
54
+ 5. **Reflect and Update Plan**
55
+ - The supervisor generates a lightweight reflection summary:
56
+ "What happened?", "Is the result valid?", "What is needed next?"
57
+ - If conditions changed, the supervisor updates the plan accordingly.
58
+ Examples:
59
+ - Skip voice screening if CV screening fails.
60
+ - Retry scheduling if the calendar shows no available slots.
61
+ - Pause and request HR confirmation when required.
62
+
63
+ 6. **Persist Memory**
64
+ - Summaries, transcripts, evaluations, and structured results are stored to prevent context bloating.
65
+ - Only relevant compact memory is injected back into future steps.
66
+
67
+ 7. **Repeat Until Complete**
68
+
69
+ ---
70
+
71
+ ## 3. Task Delegation Strategy
72
+ The supervisor delegates tasks to subagents based on rule-based planning combined with lightweight LLM reasoning.
73
+
74
+ ### Delegation Logic
75
+ - **CV Screening Agent** is invoked when a new applicant is added or a CV is updated.
76
+ - **Voice Screening Agent** is invoked when the candidate passes CV screening and HR or the plan flags them as suitable for a phone screen.
77
+ - **Scheduler Agent** is invoked once voice screening produces a valid transcript and evaluation.
78
+ - **Decision Agent** is invoked after all stages complete, or when early rejection is clear.
79
+
80
+ Each subagent returns structured outputs that the supervisor uses to drive the next step.
81
+
82
+ ---
83
+
84
+ ## 4. Adaptive Re-Planning
85
+ One of the supervisor’s core responsibilities is to respond dynamically to real-world conditions.
86
+
87
+ Examples of adaptive behaviors:
88
+
89
+ - **Tool failure**: If Gmail or Calendar returns an MCP error, the supervisor retries, selects an alternative interaction path, or defers the step.
90
+ - **Calendar constraints**: If no timeslots are available, the supervisor generates an alternate plan.
91
+ - **Candidate status shifts**: If a candidate responds late or provides new documents, the supervisor reevaluates the plan.
92
+ - **Voice call failure**: If the candidate does not pick up, the supervisor schedules a retry or sends an email follow-up.
93
+
94
+ This makes the workflow robust, autonomous, and consistent with agentic paradigms.
95
+
96
+ In unique situations, such as exceptional applicants, the agent can accellerate the timeline such as skipping stages. This is entirely discretionary and up to the agent's decision.
97
+
98
+ ---
99
+
100
+ ## 5. Context Engineering Strategy
101
+ We utilize context engineering many times in the workflow. Each subagent instance is stateless, meaning that it doesn't retain any memory or context from previous turns. This allows for reduced token usage, since information from previous applicants is not relevant for new tasks. This state is reset every time it handles a unique task, but is retained until the supervisor determines the subagent has fully completed all necessary steps.
102
+
103
+ Each time a subagent completes a task, the agent is given the full response. After the supervisor performs its next action, the subagent response is compacted into a high-level summary.
104
+
105
+ The supervisor agent itself is also stateless in a sense: its context is applicant-dependant. Real-life timelines are messy, and multiple applicants will have steps overlap. Each time the supervisor agent needs to perform a new task, it loads the context from the user it is working on, and unloads it when it is done. This way, the supervisor is able to stay focused on a specific applicant and not get confused or distracted by managing multiple applicants at the same time. The state for this agent is saved in temporary files which are deleted once the applicant has a final decision made (hire or discard).
106
+
107
+ ---
108
+
109
+ ## 6. Explainability and Dashboard Integration
110
+ The supervisor produces the trace outputs that power the Gradio dashboard.
111
+
112
+ This includes:
113
+ - Plan state (past, current, future)
114
+ - Tool call logs
115
+ - Reasoning and reflection summaries
116
+ - Active memory excerpts
117
+ - Subagent outputs
118
+ - Error messages and fallback paths
119
+
120
+ Because a single agent manages the plan, dashboard integration remains consistent and interpretable.
docs/agents/voice_screening.md ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Voice Screening MVP
2
+
3
+ ## Overview
4
+
5
+ The **Voice Screening MVP** provides a simple browser-based voice interview interface using Streamlit and OpenAI Realtime API. This is a simplified implementation that removes the complexity of LangGraph agents, Twilio telephony, and FastAPI servers.
6
+
7
+ ## Architecture
8
+
9
+ **Simple MVP Architecture:**
10
+ - **Streamlit UI**: Web interface with toggle recording button
11
+ - **WebSocket Proxy**: FastAPI proxy for browser WebSocket authentication
12
+ - **OpenAI Realtime API**: Real-time speech-to-speech via WebSocket
13
+ - **Real-time transcription**: Live transcript display
14
+ - **Real-time TTS**: Audio playback in browser with sequential queue
15
+ - **Simple backend**: Post-session analysis and database storage
16
+
17
+ ## Components
18
+
19
+ | Component | Purpose |
20
+ |------------|----------|
21
+ | **Streamlit UI** | Main interface with interview controls and transcript display |
22
+ | **HTML/JavaScript Component** | WebSocket connection via proxy, audio recording/playback with queue |
23
+ | **WebSocket Proxy** | FastAPI service to handle OpenAI authentication (browsers can't set custom headers) |
24
+ | **OpenAI Realtime API** | Handles speech-to-text and text-to-speech in real-time (gpt-4o-mini-realtime-preview) |
25
+ | **Analysis Function** | Simple GPT-4 analysis of transcript (no LangGraph) |
26
+ | **Database Utilities** | Save results to database |
27
+
28
+ ## Flow
29
+
30
+ ```text
31
+ User enters email and requests authentication code
32
+
33
+ Proxy generates 6-digit code (MVP: displayed directly; production: sent via email/SMS)
34
+
35
+ User enters email and code to verify
36
+
37
+ Proxy validates code and returns session token
38
+
39
+ User clicks "Start Interview"
40
+
41
+ Browser opens WebSocket to WebSocket Proxy (with session token in query param)
42
+
43
+ Proxy validates session token
44
+
45
+ Proxy forwards connection to OpenAI Realtime API with API key authentication
46
+
47
+ Proxy configures OpenAI session (modalities, instructions, voice, etc.)
48
+
49
+ Proxy sends greeting request to OpenAI
50
+
51
+ Agent greets candidate (first TTS response)
52
+
53
+ User clicks mic button to start recording (toggle on)
54
+
55
+ Browser streams audio chunks to OpenAI via proxy
56
+
57
+ OpenAI returns transcriptions + TTS audio in real-time
58
+
59
+ Audio chunks queued and played sequentially in browser
60
+
61
+ Transcript shown live in Streamlit UI
62
+
63
+ User clicks mic button again to stop and send (toggle off)
64
+
65
+ Audio buffer committed to OpenAI
66
+
67
+ User clicks "End Interview"
68
+
69
+ Send transcript to backend for analysis
70
+
71
+ GPT-4 analyzes transcript (sentiment, confidence, communication)
72
+
73
+ Results saved to database
74
+ ```
75
+
76
+ ## Implementation Details
77
+
78
+ ### Streamlit UI (`src/voice_screening_ui/app.py`)
79
+
80
+ **Features:**
81
+ - **Authentication screen**: Email and code input fields
82
+ - "Start Interview" button to initialize session
83
+ - Toggle microphone button (click to start, click again to stop and send)
84
+ - Live transcript display area
85
+ - Session controls (end interview, logout)
86
+ - Analysis and results display
87
+ - Database integration
88
+ - Debug panel for connection and audio troubleshooting
89
+
90
+ **Session State:**
91
+ - `session_token`: Authentication token from proxy
92
+ - `user_email`: Authenticated user's email
93
+ - `session_id`: Unique interview session identifier
94
+ - `transcript`: List of transcript entries
95
+ - `is_interview_active`: Boolean flag for active session
96
+ - `candidate_id`: Candidate UUID
97
+
98
+ ### HTML/JavaScript Component (`src/voice_screening_ui/components/voice_interface.html`)
99
+
100
+ **Features:**
101
+ - WebSocket connection to WebSocket Proxy with session token authentication
102
+ - Audio recording via browser ScriptProcessor API (PCM16)
103
+ - Audio playback via Web Audio API with sequential queue
104
+ - Real-time transcript updates
105
+ - Toggle recording (click to start/stop)
106
+ - Audio resampling from 24kHz to browser sample rate
107
+ - Debug panel for troubleshooting
108
+
109
+ **Key Functions:**
110
+ - `connectWebSocket()`: Establishes connection to WebSocket Proxy (with session token)
111
+ - `toggleRecording()`: Toggles recording state (start/stop)
112
+ - `startRecording()`: Captures microphone audio and streams to API
113
+ - `stopRecording()`: Stops recording and commits audio buffer
114
+ - `handleRealtimeMessage()`: Processes responses from OpenAI
115
+ - `queueAudioChunk()`: Queues audio chunks for sequential playback
116
+ - `processAudioQueue()`: Plays audio chunks one at a time
117
+ - `playAudioChunk()`: Decodes and plays individual TTS audio chunks
118
+
119
+ **Note:** Session configuration and greeting are now handled by the proxy, not the client.
120
+
121
+ ### Analysis Function (`src/voice_screening_ui/analysis.py`)
122
+
123
+ **Simple function** (no LangGraph):
124
+ - Receives transcript text
125
+ - Uses OpenAI GPT-4 with structured output
126
+ - Returns `VoiceScreeningOutput` with scores and summary
127
+ - No agent nodes or graph execution
128
+
129
+ ### Database Integration (`src/voice_screening_ui/utils/db.py`)
130
+
131
+ **Function:**
132
+ - `write_voice_results_to_db()`: Saves results to database
133
+ - Updates candidate status to `voice_done`
134
+ - Uses existing `VoiceScreeningResult` model
135
+
136
+ ### WebSocket Proxy (`src/voice_screening_ui/proxy.py`)
137
+
138
+ **Features:**
139
+ - **Authentication endpoints**: `/auth/login` and `/auth/verify`
140
+ - **Session management**: In-memory token storage (MVP; use Redis/DB in production)
141
+ - **WebSocket proxy**: `/ws/realtime` endpoint with session token validation
142
+ - **Session configuration**: Handles OpenAI session setup server-side
143
+ - **Greeting**: Automatically sends greeting after session configuration
144
+ - **Health check**: `/health` endpoint for monitoring
145
+
146
+ **Authentication Flow:**
147
+ 1. User requests code via `POST /auth/login` with email
148
+ 2. Proxy generates 6-digit code (MVP: returns directly; production: send via email/SMS)
149
+ 3. User verifies via `POST /auth/verify` with email and code
150
+ 4. Proxy validates and returns session token (valid for 1 hour)
151
+ 5. WebSocket connection requires `token` query parameter
152
+
153
+ **Session Configuration:**
154
+ - Moved from frontend to proxy for better security and control
155
+ - Configured automatically when WebSocket connects
156
+ - Includes modalities, instructions, voice, audio format, turn detection
157
+
158
+ ## Environment Variables
159
+
160
+ ```bash
161
+ OPENAI_API_KEY=your_openai_api_key # Required for Realtime API (stored in proxy only)
162
+ ```
163
+
164
+ **Security:**
165
+ - API key stored in proxy environment variables (never exposed to browser)
166
+ - User authentication via email/code before WebSocket access
167
+ - Session tokens expire after 1 hour
168
+ - Auth codes expire after 10 minutes
169
+ - Proxy handles all OpenAI authentication server-side
170
+
171
+ ## Usage
172
+
173
+ ### Running the Application
174
+
175
+ ```bash
176
+ # Using Streamlit directly
177
+ streamlit run src/voice_screening_ui/app.py
178
+
179
+ # Or via Docker (Streamlit service)
180
+ docker compose up voice_screening
181
+ ```
182
+
183
+ #### troubleshootips tips
184
+
185
+ - if you see a warning on env variable not being set, pass the .env manually and rebuild on down (subsequent build will be faste due to docker layer caching)
186
+ ``` bash
187
+ cd docker
188
+ docker-compose --env-file "../.env" up voice_screening -d --build
189
+ ```
190
+
191
+ - run streamlit with python path set
192
+ ``` bash
193
+ PYTHONPATH=. streamlit run src/voice_screening_ui/app.py
194
+ ```
195
+
196
+ ### User Flow
197
+
198
+ 1. Start WebSocket proxy: `docker compose up websocket_proxy` (or run `python src/voice_screening_ui/proxy.py`)
199
+ 2. Open Streamlit UI at `http://localhost:8502` (or configured port)
200
+ 3. **Authentication:**
201
+ - Enter your email address
202
+ - Click "Request Code" to get authentication code
203
+ - Enter the code and click "Verify & Login"
204
+ 4. Enter candidate email (optional for MVP)
205
+ 5. Click "Start Interview"
206
+ 6. Browser requests microphone permission
207
+ 7. WebSocket connects to proxy with session token (proxy connects to OpenAI Realtime API)
208
+ 8. Proxy configures session and sends greeting
209
+ 9. Agent greets candidate
210
+ 10. User clicks mic button to start recording
211
+ 11. User speaks, audio streams to OpenAI
212
+ 12. Transcript appears in real-time
213
+ 13. Agent responds with audio (played sequentially)
214
+ 14. User clicks mic button again to stop and send
215
+ 15. User clicks "End Interview"
216
+ 16. Click "Analyze Interview" to get results
217
+ 17. Optionally save results to database
218
+ 18. Click "Logout" to end session
219
+
220
+ ## Technical Details
221
+
222
+ ### OpenAI Realtime API
223
+
224
+ **WebSocket Connection:**
225
+ - Model: `gpt-realtime-mini`
226
+ - URL: `wss://api.openai.com/v1/realtime?model=gpt-realtime-mini`
227
+ - Headers: `Authorization: Bearer {API_KEY}`, `OpenAI-Beta: realtime=v1`
228
+ - Format: PCM16 audio at 24kHz, JSON messages
229
+ - Turn Detection: Server-side VAD with 10s silence duration (prevents auto-commit during recording)
230
+
231
+ **Key Message Types:**
232
+ - `session.update`: Configure session (modalities, voice, instructions)
233
+ - `input_audio_buffer.append`: Send audio chunks
234
+ - `input_audio_buffer.commit`: Commit audio for processing
235
+ - `response.audio_transcript.done`: Receive transcriptions
236
+ - `response.audio.delta`: Receive TTS audio chunks
237
+ - `response.text.done`: Receive text responses
238
+
239
+ ### Audio Processing
240
+
241
+ **Recording:**
242
+ - Uses browser `ScriptProcessor` API (deprecated but functional)
243
+ - Captures audio at browser sample rate (typically 44.1kHz or 48kHz)
244
+ - Converts to PCM16 format
245
+ - Encodes to base64 for WebSocket transmission
246
+ - Streams chunks via `input_audio_buffer.append`
247
+ - Commits buffer via `input_audio_buffer.commit` when recording stops
248
+
249
+ **Playback:**
250
+ - Receives base64 PCM16 audio at 24kHz
251
+ - Decodes using `DataView` for proper byte order (little-endian)
252
+ - Converts PCM16 to Float32Array
253
+ - Resamples from 24kHz to browser sample rate using `OfflineAudioContext`
254
+ - Queues chunks for sequential playback (prevents overlapping audio)
255
+ - Plays through browser audio context
256
+
257
+ ## Simplifications from Original Design
258
+
259
+ **Removed:**
260
+ - LangGraph agent complexity
261
+ - Twilio telephony integration
262
+ - FastAPI server
263
+ - Media Streams handling
264
+ - Complex state management
265
+ - Supervisor agent integration
266
+
267
+ **Kept:**
268
+ - Database models and utilities
269
+ - Analysis logic (simplified)
270
+ - Streamlit UI pattern
271
+ - OpenAI Realtime API integration
272
+
273
+ ## File Structure
274
+
275
+ ```
276
+ src/voice_screening_ui/
277
+ ├── app.py # Main Streamlit UI (with authentication screen)
278
+ ├── proxy.py # WebSocket proxy with auth endpoints and session management
279
+ ├── analysis.py # Simple analysis function
280
+ ├── components/
281
+ │ ├── voice_interface.html # HTML/JS for WebSocket and audio (no API key handling)
282
+ │ └── __init__.py
283
+ └── utils/
284
+ ├── db.py # Database utilities
285
+ └── __init__.py
286
+ ```
287
+
288
+ ## Testing
289
+
290
+ **Manual Testing:**
291
+ 1. Start Streamlit app (tested and works)
292
+ 2. Test WebSocket connection (tested and works)
293
+ 3. Test microphone access (tested and works)
294
+ 4. Test audio recording and playback (tested and works)
295
+ 5. Test transcript display (not tested)
296
+ 6. Test analysis function (doesn't work, need work, a lot of work)
297
+ 7. Test database saving (doesn't work, need work, a lot, a lot of work)
298
+
299
+ ### Verification Script
300
+ To verify the integration of the voice screener with the candidate database and static questions, you can run the provided verification script.
301
+
302
+ **Option 1: Run via Docker (Recommended)**
303
+ This uses the containerized environment which already has all dependencies and network access to the database.
304
+ ```bash
305
+ docker compose -f docker/docker-compose.yml run --rm -e POSTGRES_HOST=db websocket_proxy python tests/verify_voice_integration.py
306
+ ```
307
+
308
+ **Option 2: Run Locally**
309
+ If you prefer to run it locally, you need to install the database requirements first:
310
+ ```bash
311
+ pip install -r requirements/db.txt
312
+ python tests/verify_voice_integration.py
313
+ ```
314
+
315
+ **Known Limitations:**
316
+ - Uses deprecated `ScriptProcessor` API (should migrate to `AudioWorklet`)
317
+ - Authentication codes displayed directly in MVP (should be sent via email/SMS in production)
318
+ - Session tokens stored in-memory (should use Redis/database in production)
319
+ - Simple error handling
320
+ - Limited session management
321
+ - Audio resampling may introduce slight latency
322
+
323
+ ## Future Enhancements
324
+
325
+ - Migrate from `ScriptProcessor` to `AudioWorklet` API
326
+ - Send authentication codes via email/SMS (instead of displaying directly)
327
+ - Use Redis or database for session token storage (instead of in-memory)
328
+ - Add session persistence across page refreshes
329
+ - Improve error handling and reconnection logic
330
+ - Add recording playback
331
+ - Add interview question templates
332
+ - Optimize audio resampling performance
333
+ - Add audio level visualization
334
+ - Add rate limiting for authentication endpoints
335
+ - Add session refresh mechanism
336
+ - Integrate with supervisor agent (if needed)
docs/context_engineering/ideas.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ***Context Engineering***
2
+ ---
3
+
4
+ This file serves as inspiration for context engneering techniques that are currently being used by experts in the industry.
5
+
6
+ ***Inpsired by:***
7
+ - [Langchain](https://www.notion.so/Context-Engineering-for-Agents-2a1808527b17803ba221c2ced7eef508)
8
+ - [Video](https://www.youtube.com/watch?v=XFCkrYHHfpQ&t=217s)
9
+
10
+
11
+ ## ***`What is context engineering?`***
12
+ `The art and science to fill the context with just the right information for the next step.`
13
+
14
+ [Chroma research](https://research.trychroma.com/context-rot) shows that increasing input tokens daramatically impacts llm performance.
15
+
16
+
17
+ ## Notes:
18
+
19
+ ### 1) Tool calls
20
+ - tools calls bloat context as its added to messages list, with call itself + tool results
21
+ - hence flush or summarise tools to reduce context length and keep context dense with just imoprtant info
22
+ - furthermore tools are suually injected at sytem prompt level which bloats context as well and leads to confusion of wghich tool to use.
23
+
24
+
25
+ ### Context Offloading
26
+ ...
27
+
28
+
29
+ ### Context Compaction & Offloading
30
+
31
+
32
+
33
+
docs/entrypoint_patterns.md ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## 📄 How CV Parsing & LLM Evaluation Are Triggered — Summary
2
+
3
+ Below is a clean overview of the three architectural patterns for triggering **CV parsing** and **LLM-based CV evaluation** inside an agentic HR pipeline.
4
+
5
+ ---
6
+
7
+ ## 🧩 End-to-End Flow
8
+ 1. Candidate uploads CV
9
+ 2. System stores candidate entry in DB
10
+ 3. CV parser runs automatically
11
+ 4. Parsed CV JSON is stored in DB
12
+ 5. Orchestrator detects that parsing is done
13
+ 6. Orchestrator triggers the CV Screening Agent
14
+ 7. LLM evaluates CV and stores results
15
+ 8. Pipeline continues (voice → scheduling → final decision)
16
+
17
+ ---
18
+ ```sql
19
+ [User (Streamlit UI)]
20
+
21
+ Upload CV + metadata (HTTP POST)
22
+
23
+ [Orchestrator API]
24
+
25
+ Save CV file (local or cloud)
26
+
27
+ Write candidate entry to DB
28
+
29
+ Trigger parsing pipeline
30
+
31
+ Update parsed_cv_json + status='parsed'
32
+
33
+ Orchestrator runs CV Screening Agent
34
+
35
+ Write results to DB + status='cv_screened'
36
+
37
+ [Streamlit polls /api/status/<candidate_id>]
38
+
39
+ Display updated status + scores
40
+ ```
41
+ ---
42
+
43
+ ## 🧠 Pattern A — Orchestrator-Driven State Machine (Recommended)
44
+
45
+ The orchestrator continuously monitors the candidate’s status in the database and decides the next action based on that state.
46
+
47
+ **Flow:**
48
+ - After parsing finishes, the system sets `status = "parsed"`
49
+ - The orchestrator checks the state and sees that the next step is CV screening
50
+ - It triggers the CV Screening Agent
51
+ - Once evaluation completes, the system updates status to `status = "cv_screened"`
52
+ - The orchestrator then moves to the next stage (voice screening, etc.)
53
+
54
+ **Why this is the best choice:**
55
+ - Most “agentic” (planning + reasoning)
56
+ - Clean separation between deterministic parsing and cognitive reasoning
57
+ - Perfect fit for LangGraph orchestration
58
+ - Easy to visualize reasoning and workflow progress
59
+ - Ideal for hackathon judges (transparency + intentionality)
60
+
61
+ ---
62
+
63
+ ## 🧠 Pattern B — Event-Based Trigger (Webhook, Queue, Pub/Sub)
64
+
65
+ The parsing component emits an event like “cv_parsed” when finished.
66
+ A listener or orchestrator receives that event and immediately triggers the CV Screening Agent.
67
+
68
+ **Pros:**
69
+ - Scales well
70
+ - Good for microservice architectures
71
+
72
+ **Cons:**
73
+ - Less agentic
74
+ - Harder to show planning logic and state transitions
75
+ - More infrastructure complexity
76
+
77
+ ---
78
+
79
+ ## 🧠 Pattern C — Orchestrator Polling the Database
80
+
81
+ A loop runs every few seconds, searching for candidates whose status is “parsed” and triggering CV evaluation when found.
82
+
83
+ **Pros:**
84
+ - Very simple to implement
85
+ - Works well for demos and prototypes
86
+
87
+ **Cons:**
88
+ - Not reactive
89
+ - Less elegant
90
+ - Not as agentic or clean as Pattern A
91
+
92
+ ---
93
+
94
+ ## 🏆 Recommendation
95
+
96
+ Use **Pattern A (Orchestrator-Driven State Machine)** for the hackathon submission.
97
+
98
+ **Benefits:**
99
+ - Natural agentic behavior
100
+ - Works directly with LangGraph’s planning style
101
+ - Provides clear reasoning transparency
102
+ - Fits well with your multi-agent architecture
103
+ - Easy to show on the Gradio dashboard
104
+ - Minimal complexity while still highly principled
105
+
106
+ ---
107
+
108
+ ## 📝 TL;DR
109
+
110
+ - CV parsing should run automatically after upload
111
+ - Parsed data should be saved to the DB
112
+ - **LLM CV evaluation should NOT be triggered by upload**
113
+ - Instead, the **orchestrator detects the new state and triggers evaluation**
114
+ - Pattern A (state machine) is the cleanest and most agentic solution
docs/how_langgraph_works.md ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🧭 LangGraph Overview: Message Flow, Tool Execution & GPT-OSS Integration
2
+ LangGraph is a workflow engine for building agentic systems on top of LangChain.
3
+ It models the reasoning–action loop between models and tools using a transparent graph of nodes.
4
+
5
+ This document explains:
6
+ 1. How LangGraph message flow works
7
+ 2. How tools and tool calls are represented
8
+ 3. How your custom GPT-OSS (OpenRouter) wrapper integrates via bind_tools()
9
+
10
+ ---
11
+
12
+ ## ⚙️ Core Concept
13
+ LangGraph passes a `state` object between nodes, usually defined like this:
14
+ ```python
15
+ from typing import Annotated, List, TypedDict, Any
16
+ from langgraph.graph.message import add_messages
17
+
18
+ class State(TypedDict):
19
+ messages: Annotated[List[Any], add_messages]
20
+ ```
21
+
22
+ The `messages` list holds the entire conversation: user inputs, model responses, and tool outputs.
23
+ Each node reads this list, adds new messages, and returns an updated state.
24
+
25
+ **LangGraph uses LangChain message objects:**
26
+ - 🧑‍💼 HumanMessage — from the user
27
+ - 🤖 AIMessage — from the model (may include tool_calls)
28
+ - 🧰 ToolMessage — from a tool
29
+ - ⚙️ SystemMessage — optional context
30
+
31
+ ## 🧩 The Typical Agent Flow
32
+ ```sql
33
+ HumanMessage ─► LLMNode ─► ToolNode ─► LLMNode ─► Final Answer
34
+ ```
35
+
36
+ ### 1️⃣ Human input
37
+ ```python
38
+ input_state = {
39
+ "messages": [
40
+ HumanMessage(
41
+ content="Compute 8 * 12 using calculator tool"
42
+ )
43
+ ]
44
+ }
45
+ ```
46
+ LangGraph starts from `START` and passes this to the first node (the model).
47
+
48
+ ### 2️⃣ Model response: tool call
49
+ Your model (`ChatOpenRouter` running GPT-OSS) examines the conversation and returns an `AIMessage`:
50
+ ```json
51
+ {
52
+ "content": "",
53
+ "tool_calls": [
54
+ {
55
+ "id": "call_1",
56
+ "function": {"name": "calculator", "arguments": "{\"a\":8,\"b\":12,\"op\":\"mul\"}"}
57
+ }
58
+ ],
59
+ "finish_reason": "tool_calls"
60
+ }
61
+ ```
62
+ ✅ LangGraph detects `.tool_calls` and automatically routes the next step to the ToolNode.
63
+
64
+ ### 3️⃣ Tool execution
65
+ The ***ToolNode*** executes the requested tool and adds a `ToolMessage` to the state:
66
+ ```python
67
+ ToolMessage(
68
+ content='96.0',
69
+ name='calculator',
70
+ tool_call_id='call_1'
71
+ )
72
+ ```
73
+
74
+ ### 4️⃣ LLM continuation
75
+ The LLM now sees:
76
+ ```
77
+ [
78
+ HumanMessage(...),
79
+ AIMessage(..., tool_calls=[...]),
80
+ ToolMessage(name="calculator", content="96.0")
81
+ ]
82
+ ```
83
+
84
+ It generates a final summary message:
85
+ ```text
86
+ "The result of 8 × 12 is **96**."
87
+ ```
88
+ Since this new message has no further `tool_calls`, LangGraph ends the workflow.
89
+
90
+ ## 🧠 Internal Message Logic
91
+ | Step | Message Type | Produced By | Purpose |
92
+ | ---- | -------------- | ----------- | ------------------- |
93
+ | 1 | `HumanMessage` | user | Input |
94
+ | 2 | `AIMessage` | model | Requests tool |
95
+ | 3 | `ToolMessage` | ToolNode | Returns tool output |
96
+ | 4 | `AIMessage` | model | Final answer |
97
+
98
+
99
+ LangGraph uses conditional edges to decide whether to continue looping:
100
+ ```python
101
+ workflow.add_conditional_edges(
102
+ "agent",
103
+ lambda state: "tools" if state["messages"][-1].tool_calls else END
104
+ )
105
+ ```
106
+ This keeps running until no more tool calls are made.
107
+
108
+ ## ⚙️ Example Graph Definition
109
+ ```python
110
+ from langgraph.graph import StateGraph, START, END
111
+ from langgraph.prebuilt import ToolNode
112
+ from langchain_core.messages import HumanMessage
113
+ from langchain_core.tools import tool
114
+ from src.core.llm_providers.openrouter_llm import ChatOpenRouter
115
+
116
+ @tool
117
+ def calculator(a: float, b: float, op: str) -> float:
118
+ """Perform a basic arithmetic operation."""
119
+ if op == "add": return a + b
120
+ if op == "sub": return a - b
121
+ if op == "mul": return a * b
122
+ if op == "div": return a / b
123
+
124
+ tools = [calculator]
125
+
126
+ # Initialize GPT-OSS LLM
127
+ llm = ChatOpenRouter(model_name="openai/gpt-oss-120b", temperature=0.0)
128
+
129
+ # ✅ Bind tools — this injects tool schemas into the model's context
130
+ llm_with_tools = llm.bind_tools(tools)
131
+
132
+ def call_model(state: State) -> State:
133
+ response = llm_with_tools.invoke(state["messages"])
134
+ return {"messages": [response]}
135
+
136
+ workflow = StateGraph(State)
137
+ workflow.add_node("agent", call_model)
138
+ workflow.add_node("tools", ToolNode(tools))
139
+ workflow.add_edge(START, "agent")
140
+ workflow.add_conditional_edges(
141
+ "agent", lambda s: "tools" if s["messages"][-1].tool_calls else END
142
+ )
143
+ workflow.add_edge("tools", "agent")
144
+
145
+ agent = workflow.compile()
146
+ input_state = {"messages": [HumanMessage(content="Compute 8 * 12 using calculator tool")]}
147
+ print(agent.invoke(input_state))
148
+ ```
149
+
150
+ ***>>> Check `notebooks/playground.ipynb` to see it in action!***
151
+
152
+ ```mermaid
153
+ graph TD;
154
+ __start__(<p>__start__</p>)
155
+ agent(agent)
156
+ tools(tools)
157
+ __end__(<p>__end__</p>)
158
+ __start__ --> agent;
159
+ agent -->|tool_calls| tools;
160
+ tools --> agent;
161
+ agent -->|no tool_calls| __end__;
162
+ classDef default fill:#f2f0ff,line-height:1.2
163
+ classDef first fill-opacity:0
164
+ classDef last fill:#bfb6fc
165
+ ```
166
+
167
+ ## 🧩 How bind_tools() Works Internally
168
+ `bind_tools()` is the bridge between LangGraph and your LLM.
169
+ When you call:
170
+
171
+ ```python
172
+ llm_with_tools = llm.bind_tools(tools)
173
+ ```
174
+
175
+ LangChain:
176
+ 1. Extracts each tool's name, description, and argument schema.
177
+ 2. Converts them into an OpenAI function-calling schema JSON block (like `tools=[{"type":"function","function":{"name":...}}]`).
178
+ 3. Attaches that schema to the model's context before each inference call.
179
+ So GPT-OSS sees an augmented prompt like this:
180
+ > “You have access to the following tools:
181
+ > calculator(a: float, b: float, op: str) — Perform a basic arithmetic operation.”
182
+
183
+
184
+ During inference, the model can reason (internally) about which tool to call and output structured JSON like:
185
+ ```json
186
+ {
187
+ "tool_calls": [{
188
+ "function": {
189
+ "name": "calculator",
190
+ "arguments": "{\"a\":8,\"b\":12,\"op\":\"mul\"}"
191
+ }
192
+ }]
193
+ }
194
+ ```
195
+
196
+
197
+ ---
198
+
199
+ ## 🧱 GPT-OSS Integration via ChatOpenRouter
200
+ To connect GPT-OSS via OpenRouter, use your wrapper:
201
+ ```python
202
+ # src/core/llm_providers/openrouter_llm.py
203
+ from langchain_openai import ChatOpenAI
204
+ from pydantic_settings import BaseSettings, SettingsConfigDict
205
+
206
+ class OpenRouterSettings(BaseSettings):
207
+ OPENROUTER_API_KEY: str
208
+ model_config = SettingsConfigDict(env_file=".env", extra="ignore")
209
+
210
+ class ChatOpenRouter(ChatOpenAI):
211
+ """OpenRouter wrapper for GPT-OSS and other open models."""
212
+
213
+ def __init__(
214
+ self,
215
+ model_name: str = "openai/gpt-oss-120b",
216
+ base_url: str = "https://openrouter.ai/api/v1",
217
+ temperature: float = 0.2,
218
+ **kwargs,
219
+ ):
220
+ settings = OpenRouterSettings()
221
+ super().__init__(
222
+ model_name=model_name,
223
+ openai_api_base=base_url,
224
+ openai_api_key=settings.OPENROUTER_API_KEY,
225
+ temperature=temperature,
226
+ **kwargs,
227
+ )
228
+ ```
229
+ Then simply:
230
+ ```python
231
+ llm = ChatOpenRouter()
232
+ llm_with_tools = llm.bind_tools(tools)
233
+ ```
234
+ ✅ This passes your validated API key to the OpenRouter endpoint.
235
+
236
+ ✅ bind_tools() adds your tool schemas to the model input so GPT-OSS knows which functions exist.
237
+
238
+ ✅ LangGraph handles execution and looping automatically.
239
+
240
+
241
+ ---
242
+
243
+ ## 🔁 Full Flow Recap
244
+
245
+ | Step | Component | What Happens |
246
+ | ---- | ---------------------- | ---------------------------------------------------------- |
247
+ | 1 | `ChatOpenRouter` | Sends messages to GPT-OSS via OpenRouter API |
248
+ | 2 | `bind_tools()` | Injects tool schema into model context |
249
+ | 3 | `AIMessage.tool_calls` | Model outputs structured tool call |
250
+ | 4 | `ToolNode` | Executes the requested function |
251
+ | 5 | `ToolMessage` | Returns tool result to model |
252
+ | 6 | `AIMessage` | Model produces natural-language final answer |
253
+ | ✅ | LangGraph | Orchestrates routing and maintains full conversation state |
254
+
255
+
256
+ ## ✅ TL;DR
257
+ - LangGraph represents an agent loop as a message-passing graph.
258
+ - Messages include `HumanMessage`, `AIMessage`, and `ToolMessage`.
259
+ - `bind_tools()` injects your tool schemas into the LLM's context so it can call them.
260
+ - The ToolNode executes the functions and feeds results back into the loop.
261
+ - Your `ChatOpenRouter` wrapper lets GPT-OSS models participate in this system seamlessly.
262
+
docs/mcp/gmail_mcp_gcp_setup.md ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ***`Gmail MCP – GCP Setup (Terraform + Bash)`***
2
+
3
+ This folder provisions the minimum GCP infrastructure to run the [Gmail MCP server](https://github.com/theposch/gmail-mcp/tree/main) without requiring billing:
4
+ - Creates (or adopts) a ***GCP project***
5
+ - Enables ***gmail.googleapis.com***
6
+ - Grants your user:
7
+ - `roles/editor`
8
+ - `roles/serviceusage.serviceUsageAdmin`
9
+ Prints console links to finish OAuth (consent screen + Desktop client)
10
+ > Billing is **not required** for Gmail API or OAuth Desktop client.
11
+
12
+ ## ***Prerequisites***
13
+ - **Terraform** ≥ 1.6
14
+ - **gcloud** (optional but useful for verifying/importing projects)
15
+ - A Google account (you'll also add it as a **Test user** on the OAuth consent screen)
16
+
17
+ ## Files
18
+ - `versions.tf` – provider & Terraform version pins
19
+ - `providers.tf` – Google provider config (uses project_id and region)
20
+ - `variables.tf` – input variables
21
+ - `main.tf` – project, Gmail API enablement, IAM bindings
22
+ - `outputs.tf` – project IDs and console URLs
23
+ - `terraform.tfvars` – team defaults (simple `key = "value"` pairs)
24
+
25
+ Example `terraform.tfvars`:
26
+ ```python
27
+ project_id = "gradio-hackathon-25"
28
+ project_name = "Gradio Agent MCP Hackathon 25"
29
+ user_email = "hr.cjordan.agent.hack.winter25@gmail.com"
30
+ # region = "europe-west3" # optional
31
+ ```
32
+
33
+ ## ***Quick Start (recommended: use the scripts)**
34
+ From the ***repo root***:
35
+ 1. **Authenticate gcloud + ADC**
36
+ ```bash
37
+ chmod +x scripts/gcp_setup.sh
38
+ ./scripts/gcp_setup.sh
39
+ ```
40
+
41
+ 2. **Apply Terraform with smart defaults + auto-import**
42
+ ```bash
43
+ chmod +x scripts/terraform_apply.sh
44
+ ./scripts/terraform_apply.sh
45
+ ```
46
+
47
+ - The script **prompts** for `project_id`, `project_name`, `user_email`.
48
+ - Press ***Enter*** to use defaults from `terraform/terraform.tfvars`.
49
+ - If the project already exists, it is **auto-imported** to avoid `409 alreadyExists`.
50
+
51
+ ---
52
+
53
+ ## ***Manual Usage (alternative)***
54
+ Run these from this `terraform/` directory:
55
+ ```bash
56
+ terraform init
57
+
58
+ # If the project already exists, import it so Terraform manages it:
59
+ # terraform import google_project.project <your-project-id>
60
+
61
+ terraform apply
62
+ ```
63
+
64
+ Override values:
65
+
66
+ ```bash
67
+ terraform apply \
68
+ -var="project_id=my-mcp-project" \
69
+ -var="project_name=My MCP Project" \
70
+ -var="user_email=you@example.com"
71
+ ```
72
+
73
+ Or via env vars:
74
+ ```bash
75
+ export TF_VAR_project_id="my-mcp-project"
76
+ export TF_VAR_project_name="My MCP Project"
77
+ export TF_VAR_user_email="you@example.com"
78
+ terraform apply
79
+ ```
80
+
81
+ ## **Outputs**
82
+ - `project_id` / `project_number`
83
+ - `gmail_api_service` — `"gmail.googleapis.com"` (resource present ⇒ enabled)
84
+ - `console_oauth_consent_screen_url` — configure consent (External, Test user, add scope)
85
+ - `console_oauth_credentials_url` — create ***OAuth 2.0 Client ID*** (Desktop app)
86
+
87
+ ## **Final OAuth Setup (one-time, in Console)**
88
+
89
+ Terraform cannot create the **OAuth consent screen** or **Desktop OAuth client**, so you'll do these two steps once in the Google Cloud Console.
90
+ This setup allows your **local Gmail MCP server** to access Gmail via OAuth securely.
91
+
92
+ > 💡 **Tip:** In the new Google Cloud UI, the old “Scopes” and “Test users” tabs are now under **Data access** and **Audience** in the left sidebar.
93
+
94
+ ---
95
+
96
+ ### 1️⃣ **Configure the OAuth Consent Screen**
97
+
98
+ **Purpose:** Identify your app to Google and specify who can use it during testing.
99
+
100
+ 1. Open the link printed in Terraform outputs:
101
+ → `console_oauth_consent_screen_url`
102
+
103
+ 2. If prompted, choose **User type: External**, then click **Create**.
104
+
105
+ 3. Fill out **App info**:
106
+ - **App name:** `Gmail MCP Local`
107
+ - **User support email:** your Gmail address
108
+ - **Developer contact email:** your Gmail address
109
+ - Click **Save and Continue**
110
+
111
+ 4. In the left sidebar, go to **Data access**
112
+ - Click **Add or remove scopes**
113
+ - Add the following scopes:
114
+ ```text
115
+ https://www.googleapis.com/auth/gmail.modify
116
+ openid
117
+ https://www.googleapis.com/auth/userinfo.email
118
+ ```
119
+ ✅ *These provide read, send, and modify access — no extra Gmail scopes required.*
120
+
121
+ 5. Go to **Audience** (left sidebar)
122
+ - Under **Test users**, click **Add users**
123
+ - Add your Gmail account address
124
+ - Click **Save**
125
+
126
+ 6. Go to **Summary** and confirm:
127
+ - User type → **External**
128
+ - Publishing status → **Testing**
129
+ - Test users → your Gmail account
130
+ - Scopes → shows Gmail modify, openid, userinfo.email
131
+
132
+ ---
133
+
134
+ ### 2️⃣ **Create a Desktop OAuth Client**
135
+
136
+ **Purpose:** This provides the credentials your **local MCP server** uses to initiate the OAuth flow.
137
+
138
+ 1. Open the second Terraform output link:
139
+ → `console_oauth_credentials_url`
140
+
141
+ 2. Click **Create credentials → OAuth client ID**
142
+
143
+ 3. Choose:
144
+ - **Application type:** `Desktop app`
145
+ - **Name:** `gmail-mcp-desktop`
146
+
147
+ 4. Click **Create**, then **Download JSON**, and move it into the expected directory:
148
+ ```bash
149
+ mkdir -p ~/.gmail-mcp
150
+ mv ~/Downloads/client_secret_*.json ~/.gmail-mcp/credentials.json
151
+ ```
152
+
153
+ ### ⚠️ ***Important: Two Different JSONs***
154
+
155
+ - The file from:
156
+ ```bash
157
+ gcloud auth application-default login
158
+ ```
159
+ is your ***Application Default Credentials (ADC)*** — used by Terraform and `gcloud`.
160
+ It is ***not*** the same as the Desktop OAuth client JSON.
161
+ The Gmail MCP server requires the ***Desktop OAuth client JSON*** you downloaded.
162
+ → Place it at `~/.gmail-mcp/credentials.json`.
163
+
164
+ ### 🚀 ***When You Run the MCP Server***
165
+ The server will open a browser window asking you to sign in and approve access.
166
+ You'll see your app name (`Gmail MCP Local`) and the Gmail modify scope.
167
+ After approving, tokens are cached locally (usually `~/.gmail-mcp/token.json`), so you won't need to approve again.
168
+
169
+
170
+ ---
171
+
172
+ ### ⚙️ **Install Required Tools**
173
+
174
+ Before testing or running the Gmail MCP server, make sure the following tools are installed:
175
+
176
+ #### 🟣 1. Install `uv`
177
+ `uv` is a fast Python package manager used to run the Gmail MCP server.
178
+
179
+ Check if it's already installed:
180
+ ```bash
181
+ uv --version
182
+ ```
183
+ If not, install it:
184
+
185
+ ```bash
186
+ curl -LsSf https://astral.sh/uv/install.sh | sh
187
+ ```
188
+
189
+ Verify:
190
+ ```
191
+ uv --version
192
+ ```
193
+ #### 🟠 2. Install Node.js (includes `npm` and `npx`)
194
+ npx is used to run the MCP Inspector, which lets you test your Gmail MCP server locally.
195
+ ```bash
196
+ brew install node
197
+ ```
198
+
199
+ ### 🧪 ***Testing Locally with MCP Inspector***
200
+ Once toBefore connecting to Claude Desktop or a LangGraph agent, you can visually inspect and test your Gmail MCP server using the ***MCP Inspector*** web UI.
201
+
202
+ #### 1️⃣ **Run with simple path (direct server entry)**
203
+ Use this if you're already inside the ``gmail-mcp directory or the script path resolves cleanly:
204
+ ```bash
205
+ npx @modelcontextprotocol/inspector uv run /Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/gmail-mcp/src/gmail/server.py \
206
+ --creds-file-path ~/.gmail-mcp/credentials.json \
207
+ --token-path ~/.gmail-mcp/token.json
208
+ ```
209
+
210
+ #### 2️⃣ **Run with full project context (recommended)**
211
+ This variant is more robust and works regardless of your working directory, because it explicitly tells `uv` which project directory to use and where your binaries are.
212
+
213
+ ```bash
214
+ npx @modelcontextprotocol/inspector \
215
+ /Users/sebastianwefers/.local/bin/uv \
216
+ --directory /Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/gmail-mcp \
217
+ run gmail \
218
+ --creds-file-path ~/.gmail-mcp/credentials.json \
219
+ --token-path ~/.gmail-mcp/token.json
220
+ ```
221
+
222
+ #### 🔍 What Happens
223
+ When you run either command, you should see output similar to:
224
+ ```bash
225
+ Starting MCP inspector...
226
+ ⚙️ Proxy server listening on localhost:6277
227
+ 🔑 Session token: 8498939effc01e03c1b879efa72768e45608056ef1ad45e5c80344a7d9362a72
228
+ Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
229
+
230
+ 🚀 MCP Inspector is up and running at:
231
+ http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=8498939effc01e03c1b879efa72768e45608056ef1ad45e5c80344a7d9362a72
232
+
233
+ 🌐 Opening browser...
234
+
235
+ ```
236
+
237
+ This automatically opens a local browser window to the MCP Inspector UI, connected to your Gmail MCP server.
238
+
239
+ ✅ Expected behavior:
240
+ - On first run, a browser window will prompt you to log in and approve access.
241
+ - After successful OAuth, a token file will be created:
242
+ ```bash
243
+ ~/.gmail-mcp/token.json
244
+ ```
245
+ - Subsequent runs reuse this token — no re-auth required.
246
+ - You can now explore, invoke, and inspect your Gmail MCP tools visually (e.g., `listEmails`, `sendEmail`, `modifyLabel`, etc.) right from the web UI.
247
+
248
+ ### 💻 ***Connecting the Gmail MCP Server to Claude Desktop***
249
+ 1. Open your Claude Desktop configuration file:
250
+ ```bash
251
+ nano ~/Library/Application Support/Claude/claude_desktop_config.json
252
+ ```
253
+ 2. Add this block (update paths if necessary):
254
+ ```json
255
+ {
256
+ "mcpServers": {
257
+ "gmail": {
258
+ "command": "uv",
259
+ "args": [
260
+ "--directory",
261
+ "/Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/gmail-mcp",
262
+ "run",
263
+ "gmail",
264
+ "--creds-file-path",
265
+ "/Users/sebastianwefers/.gmail-mcp/credentials.json",
266
+ "--token-path",
267
+ "/Users/sebastianwefers/.gmail-mcp/token.json"
268
+ ]
269
+ }
270
+ }
271
+ }
272
+ ```
273
+ 3. Save the file and restart Claude Desktop.
274
+
275
+ 4. Open ***Settings → Model Context Protocol → Add Server***, then connect to gmail.
276
+
277
+ Claude will now be able to:
278
+ - 📥 Read emails
279
+ - ✉️ Compose drafts
280
+ - 🏷 Send and modify Gmail messages directly from your account.
281
+
282
+ — all directly via your Gmail MCP server.
283
+
284
+
285
+ ## 🧩 Why Deleting token.json Fixes the “invalid_grant” Error
286
+ The error occurs because the stored refresh token in token.json is expired or revoked, so Google rejects all refresh attempts.
287
+ Deleting the file forces the app to start a new OAuth flow, prompting you to log in again and generating a new, valid refresh token — which restores access to the Gmail API.
288
+
289
+ ```bash
290
+ # 1. Remove the invalid cached token
291
+ rm /Users/sebastianwefers/Desktop/projects/recruitment-agent-mcp-hackathon-winter25/secrets/gmail-mcp/token.json
292
+
293
+
294
+ # 2. Re-run the Gmail MCP server (which triggers OAuth again)
295
+ python -m src.mcp_servers.gmail_mcp
296
+ ```
297
+
298
+ Then, when the script printed a Google sign-in URL, you:
299
+ 1. Opened it in your browser,
300
+ 2. Logged in to your Google account,
301
+ 3. Approved the Gmail API access,
302
+ 4. And the new valid token.json was automatically recreated at:
303
+ ```bash
304
+ ~/.gmail-mcp/token.json
305
+ ```
docs/mcp/google_tools_mcp.md ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Google Calendar and GMail Tools / MCP
2
+
3
+ ## 1) ***`Base setup`***
4
+ ### 1.1) ***GMail Account***
5
+
6
+ ### 1.2) ***Google Cloud***
7
+
8
+ #### Terraform Modifications (Minimal)
9
+ You can extend your existing Gmail Terraform to include Calendar support.
10
+ Add these to your `main.tf`:
11
+ ```bash
12
+ # Enable the Google Calendar API
13
+ resource "google_project_service" "calendar_api" {
14
+ project = google_project.project.project_id
15
+ service = "calendar.googleapis.com"
16
+ disable_on_destroy = false
17
+ }
18
+ ```
19
+ And if you want, you can add an output for convenience:
20
+ ```bash
21
+ output "console_calendar_api_url" {
22
+ value = "https://console.cloud.google.com/apis/library/calendar.googleapis.com?project=${google_project.project.project_id}"
23
+ }
24
+ ```
25
+ After adding, re-run your scripts:
26
+ ```bash
27
+ cd terraform
28
+ terraform apply
29
+ ```
30
+ This enables the Calendar API in the same project your Gmail MCP is using — so you don't have to create a second one.
31
+
32
+ Terraform will:
33
+ 1. Detect that you already have a project and Gmail API from before.
34
+ 2. Notice the new Calendar API resource in ``main.tf.
35
+ 3. Apply only that new change (plus any small diff in IAM roles if needed).
36
+
37
+ 💡 What Happens Internally
38
+ When you run `terraform apply`, Terraform will:
39
+ - Read your current state file (`terraform.tfstate`).
40
+ - Query GCP to check what's already deployed.
41
+ - Compute a plan (the difference between your state and the `.tf` files).
42
+
43
+ #### 🔑 OAuth Setup — Shared Consent Screen
44
+ You do not need a new consent screen — just reuse your existing one (Gmail MCP Local) and add the Calendar scope.
45
+
46
+ Go to:
47
+ 👉 [Google Cloud Console → APIs & Services → OAuth consent screen → Edit app → Data access → Add scopes]
48
+ Add this scope:
49
+ ```arduino
50
+ https://www.googleapis.com/auth/calendar
51
+ ```
52
+ You'll now have Gmail + Calendar under one consent.
53
+ Then, create a ***second OAuth client***:
54
+ Application type: Desktop app
55
+ Name: `calendar-mcp-desktop`
56
+ Download the credentials JSON → save it to:
57
+ ```bash
58
+ ~/.calendar-mcp/credentials.json
59
+ ```
60
+ The Calendar MCP server will then use this credentials file when it first authenticates.
61
+
62
+ #### 🧩 MCP Client Config (Claude or LangGraph)
63
+ Just add a new block alongside your Gmail entry.
64
+ For Claude Desktop (`claude_desktop_config.json`)
65
+ ```json
66
+ {
67
+ "mcpServers": {
68
+ "gmail": {
69
+ "command": "uv",
70
+ "args": [
71
+ "--directory",
72
+ "/Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/gmail-mcp",
73
+ "run",
74
+ "gmail",
75
+ "--creds-file-path",
76
+ "/Users/sebastianwefers/.gmail-mcp/credentials.json",
77
+ "--token-path",
78
+ "/Users/sebastianwefers/.gmail-mcp/token.json"
79
+ ]
80
+ },
81
+ "google_calendar": {
82
+ "command": "uv",
83
+ "args": [
84
+ "--directory",
85
+ "/Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/calendar-mcp",
86
+ "run",
87
+ "calendar"
88
+ ]
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ For LangGraph:
95
+ ```python
96
+ client = MultiServerMCPClient({
97
+ "gmail": {
98
+ "command": "uv",
99
+ "args": [
100
+ "--directory", "/Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/gmail-mcp",
101
+ "run", "gmail",
102
+ "--creds-file-path", "/Users/sebastianwefers/.gmail-mcp/credentials.json",
103
+ "--token-path", "/Users/sebastianwefers/.gmail-mcp/token.json"
104
+ ],
105
+ "transport": "stdio"
106
+ },
107
+ "google_calendar": {
108
+ "command": "uv",
109
+ "args": [
110
+ "--directory", "/Users/sebastianwefers/Desktop/development/recruitment-agent-mcp-hackathon-winter25/src/mcp_servers/calendar-mcp",
111
+ "run", "calendar"
112
+ ],
113
+ "transport": "stdio"
114
+ }
115
+ })
116
+ ```
117
+ #### Environment Variables (.env)
118
+ Create the .env in your calendar-mcp repo root, just like described in its README:
119
+ ```bash
120
+ GOOGLE_CLIENT_ID='YOUR_CLIENT_ID'
121
+ GOOGLE_CLIENT_SECRET='YOUR_CLIENT_SECRET'
122
+ TOKEN_FILE_PATH='.gcp-saved-tokens.json'
123
+ OAUTH_CALLBACK_PORT=8080
124
+ CALENDAR_SCOPES='https://www.googleapis.com/auth/calendar'
125
+ ```
126
+ ⚠️ Make sure the redirect URI matches:
127
+ ```bash
128
+ http://localhost:8080/oauth2callback
129
+ ```
130
+ You'll go through one browser OAuth login on first run, and then `.gcp-saved-tokens.json` will be created — no need to repeat.
131
+
132
+
133
+ ## 2) ***`Model Context Protocol`***
134
+ **References**
135
+ - [Official MCP Docs](https://modelcontextprotocol.io/docs/getting-started/intro)
136
+ - [MCP Crash Course by YouTuber & AI Engineer Dave Ebbelaar](https://www.youtube.com/watch?v=5xqFjh56AwM&t=761s)
137
+ - *Existing Repo's*
138
+ - [Curated list of MCP servers](https://github.com/modelcontextprotocol/servers) hosted by `MCP` themselves.
139
+ - [Goole Calendar](https://github.com/deciduus/calendar-mcp/blob/main/README.md)
140
+ - calendar repo alterntives:
141
+ - https://github.com/nspady/google-calendar-mcp/tree/main/src/tools
142
+ ```psql
143
+ # Calendar MCP (Dual Layer)
144
+ LLM Agent
145
+
146
+ │ JSON-RPC over STDIO
147
+
148
+ MCP Bridge (mcp_bridge.py)
149
+ │ HTTP requests to localhost:8000
150
+
151
+ FastAPI Server (server.py)
152
+
153
+ └── Google Calendar API (OAuth + REST)
154
+ ```
155
+
156
+ - [GMail](https://github.com/theposch/gmail-mcp/blob/main/README.md)
157
+ ```psql
158
+ # Gmail MCP (Pure MCP)
159
+ LLM Agent
160
+
161
+ │ JSON-RPC over STDIO
162
+
163
+ Gmail MCP Server
164
+
165
+ └── Gmail API (OAuth + REST)
166
+ ```
167
+ - [Gmail](https://github.com/MCP-Mirror/Samarth2001_gmail-mcp)
168
+ - [Gmail](https://github.com/jasonsum/gmail-mcp-server)
169
+
170
+
171
+ ## 🧱 1️⃣ Compatibility Breakdown
172
+ | Area | Gmail MCP | Calendar MCP | Compatible? | Notes |
173
+ | ------------------- | ---------------------------------------------- | ----------------------------------------------- | ----------- | --------------------------------------------------------------------------- |
174
+ | **Transport** | MCP via STDIO | MCP via STDIO (through FastAPI bridge) | ✅ | Works out of the box with same client setup. |
175
+ | **Auth Type** | OAuth 2.0 Desktop Client | OAuth 2.0 Desktop Client | ✅ | Identical flow; can reuse same consent screen + test users. |
176
+ | **Scopes** | `https://www.googleapis.com/auth/gmail.modify` | `https://www.googleapis.com/auth/calendar` | ✅ | Different scopes, but both can live under one consent screen. |
177
+ | **Terraform** | Creates project, enables Gmail API, sets roles | Just needs Calendar API enabled too | ✅ | Add one more API + scope to Terraform config. |
178
+ | **Token Storage** | `~/.gmail-mcp/token.json` | `.gcp-saved-tokens.json` | ✅ | Each uses its own token file; keep separate to avoid refresh token mix-ups. |
179
+ | **Runtime** | `uv` stdio server | `python run_server.py` (auto-switches to stdio) | ✅ | You can use `uv` for both, if you prefer consistency. |
180
+ | **MCP Integration** | Claude / LangGraph via config | Same | ✅ | Just add another entry under `mcpServers`. |
intro.md ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ***`Gradio Agents & MCP Hackathon Winter Edition 2025`***
2
+
3
+ ## 🏁 Overview
4
+ This repository hosts our team's submission for **Track 2: MCP in Action** in the [MCP's 1st Birthday Hackathon](https://huggingface.co/MCP-1st-Birthday).
5
+
6
+ Our goal is to build an **autonomous agentic system** that demonstrates:
7
+ - **Planning, reasoning, and execution**
8
+ - Integration of **custom tools, MCP tools, or external APIs**
9
+ - Effective **context engineering**
10
+ - Clear, practical **user value**
11
+
12
+ We'll use **LangGraph** as our orchestration backbone for building multi-turn, tool-using, and context-aware agents.
13
+
14
+ > ***`Check hackathon README for detilaed requirements.`***
15
+
16
+ ## 🧠 ***`Tools & Frameworks`***
17
+
18
+ - 🧩 [LangGraph](https://docs.langchain.com/oss/python/langgraph/overview): for multi-agent orchestration and planning
19
+ - Why & how they built [LangGraph for production agents](https://blog.langchain.com/building-langgraph/)
20
+ - 🧠 **LLM Engines:** [OpenAI](https://openai.com) / [Anthropic](https://www.anthropic.com) — reasoning and planning models
21
+ - gpt-oss inference providers
22
+ - [Open Router](https://openrouter.ai/openai/gpt-oss-20b):
23
+ - LangChain Wrapper: https://github.com/langchain-ai/langchain/discussions/27964
24
+ - [TogetherAI](https://www.together.ai/openai)
25
+ - 💬 [Gradio](https://www.gradio.app/): for the UI and context-engineering demos
26
+ - ⚙️ [MCP](https://modelcontextprotocol.io/docs/getting-started/intro) Tools: standardized interfaces for Gmail, Google Calendar, Voice technologies and other APIs
27
+ - ☁️ [Google Cloud Platform](https://cloud.google.com): optional backend for hosting MCP servers and integrated services
28
+ - 📞 [Twilio](https://www.twilio.com/en-us): enables automated voice calls and candidate interactions
29
+ - 🔊 [ElevenLabs](https://elevenlabs.io): (optional) natural text-to-speech for realistic voice screenings
30
+ - 🎙️ [Whisper-based Transcription API](https://whisperapi.com) (or [OpenAI Whisper API](https://platform.openai.com/docs/guides/speech-to-text) ) — for speech-to-text functionality in voice interviews
31
+ - 🧭 [Langfuse](https://langfuse.com) or [LangSmith](https://docs.langchain.com/langsmith/quick-start-studio): debugging, observability, and trace visualization
32
+ - 📄 [Docling](https://www.docling.ai): for parsing and analyzing uploaded CV documents
33
+ - 🧱 [Pydantic](https://docs.pydantic.dev/latest/): for structured outputs and data validation
34
+ - 🔀 [Parlant](https://github.com/emcie-co/parlant): enables agents to handle multi-intent, free-form conversations by dynamically activating relevant guidelines instead of rigidly routing to a single sub-agent — solving the context fragmentation problem inherent in traditional LangGraph supervisor patterns.
35
+
36
+ ## 📚 ***`References for Context Engineering`***
37
+
38
+ - [**Context Engineering for AI Agents — Manus Blog**](https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus)
39
+ - [**YouTube Talk Manus**](https://www.youtube.com/watch?v=6_BcCthVvb8&start=2525)
40
+ - [**LangGraph Overview**](https://docs.langchain.com/oss/python/langgraph/overview)
41
+ - https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
42
+ - https://medium.com/fundamentals-of-artificial-intelligence/mitigate-context-poisoning-in-ai-agents-using-context-engineering-96cf40dbb38d
43
+ - https://blog.langchain.com/context-engineering-for-agents/
44
+ - **langgraph implementations**
45
+ - [video]((https://www.youtube.com/watch?v=nyKvyRrpbyY))
46
+ - [good notebooks](https://github.com/langchain-ai/how_to_fix_your_context/blob/main/notebooks/utils.py)
47
+ - [Langgraph summary of what frontier labs and firms apply](https://www.youtube.com/watch?v=XFCkrYHHfpQ)
48
+
49
+ These resources guide our approach to **memory management, planning transparency, and tool orchestration** in autonomous agents.
50
+
51
+ ## 🧾 ***`HR Candidate Screening Multi-Agent System`***
52
+ An autonomous HR assistant that streamlines early recruitment through five steps:
53
+ 1. **CV Upload (Application)** — candidate applications uploaded and parsed
54
+ 2. **CV Screening** — rank and shortlist candidates using LLM reasoning
55
+ 3. **Voice Screening** — invite and coordinate interviews using a voice agent.
56
+ 4. **Person-to-Person Screening** — schedule HR interviews via Google Calendar integration
57
+ 5. **Decision** — generate a concise summary and notify HR
58
+
59
+ > **`NOTE`**
60
+ > - Final decision of whether candidate will be hired is made by human.
61
+ > - Just automate the boring, tedious stuff while keeping human final decision in the loop.
62
+
63
+ **Architecture:**
64
+ 1. **Main Planner Agent**: orchestrates the workflow
65
+ 2. **Subagents**:
66
+ - CV Screening Agent
67
+ - Voice Screening Agent
68
+ - Meeting Scheduler Agent
69
+ 3. **Tools (via MCP)** connect to Gmail, Calendar, and Voice APIs.
70
+ 4. **Database** stores both candidate info and persistent agent memory.
71
+ 5. **Gradio UI** visualizes workflow, reasoning, and results.
72
+ ```mermaid
73
+ flowchart TD
74
+ subgraph MainAgent["🧠 Main Planner Agent"]
75
+ A1["Plans • Reasons • Executes"]
76
+ end
77
+
78
+ subgraph Subagents["🤖 Subagents"]
79
+ S1["📄 CV Screening"]
80
+ S2["🎙️ Voice Screening"]
81
+ S3["📅 Scheduling"]
82
+ S4["🧾 Decision Summary"]
83
+ end
84
+
85
+ subgraph Tools["⚙️ MCP & External Tools"]
86
+ T1["📧 Gmail"]
87
+ T2["🗓️ Google Calendar"]
88
+ T3["🗣️ Voice API"]
89
+ end
90
+
91
+ subgraph Data["🗄️ Database"]
92
+ D1["Candidate Data"]
93
+ D2["Context Memory (Cognitive Offloading)"]
94
+ end
95
+
96
+ subgraph UI["💬 Gradio Dashboard"]
97
+ U1["HR View & Interaction"]
98
+ end
99
+
100
+ %% Connections
101
+ MainAgent --> Subagents
102
+ Subagents --> Tools
103
+ Subagents --> Data
104
+ MainAgent --> Data
105
+ MainAgent --> UI
106
+ ```
107
+
108
+ **GCP Setup for Judges:**
109
+ A single demo Gmail/Calendar account (`scionhire.demo@gmail.com`) is pre-authorized via OAuth, with stored credentials in `.env`.
110
+ Judges can run or view the live demo without any credential setup, experiencing real Gmail + Calendar automation safely.
111
+
112
+ We use **hierarchical planning**:
113
+ - **Main Agent:** decides next step in the workflow (plan, adapt, replan)
114
+ - **Subagents:** specialized executors (screening, scheduling, summarization)
115
+ - **Memory State:** tracks plan progress and tool results
116
+ - **Dashboard Visualization:** shows active plan steps and reasoning traces for transparency
117
+
118
+ 🧠 Why This Is an Agent (Not Just a Workflow)
119
+
120
+ | Criterion | Workflow | Our System |
121
+ |------------|-----------|-------------|
122
+ | **Autonomy** | Executes fixed sequence of steps | Main agent decides next actions without manual triggers |
123
+ | **Planning** | Predefined order (A → B → C) | Main agent generates and adapts a plan (e.g., skip, retry, re-order) |
124
+ | **Reasoning** | No decision logic | Uses LLM reasoning to evaluate outputs and choose next subagent |
125
+ | **Context Awareness** | Stateless | Maintains shared memory of candidates, progress, and outcomes |
126
+ | **Adaptation** | Fails or stops on error | Re-plans (e.g., if calendar slots full or candidate unresponsive) |
127
+
128
+ ✅ **Therefore:** it qualifies as an *agentic system* because it **plans, reasons, and executes** autonomously rather than following a static workflow.
129
+
130
+ ## ***`Project Structure`***
131
+ ```
132
+ agentic-hr/
133
+
134
+ ├── 📁 src/
135
+ │ │
136
+ │ ├── 📁 core/
137
+ │ │ │ ├── base_agent.py # Abstract BaseAgent (LangGraph-compatible)
138
+ │ │ │ ├── supervisor.py # Supervisor agent (LangGraph graph assembly)
139
+ │ │ │ ├── state.py # Shared AgentState + context window
140
+ │ │ │ ├── planner.py # High-level planning logic
141
+ │ │ │ └── executor.py # Graph executor / runner
142
+ │ │
143
+ │ ├── 📁 agents/
144
+ │ │ │
145
+ │ │ ├── 📁 cv_screening/
146
+ │ │ │ │ ├── agent.py # CVScreeningAgent implementation
147
+ │ │ │ │ ├── 📁 tools/
148
+ │ │ │ │ │ ├── doc_parser.py
149
+ │ │ │ │ │ ├── normalize_skills.py
150
+ │ │ │ │ │ ├── rank_candidates.py
151
+ │ │ │ │ │ └── match_to_jd.py
152
+ │ │ │ │ └── 📁 schemas/
153
+ │ │ │ │ ├── cv_schema.py # Parsed CV Pydantic schema
154
+ │ │ │ │ └── jd_schema.py # Job description schema
155
+ │ │ │
156
+ │ │ ├── 📁 voice_screening/
157
+ │ │ │ │ ├── agent.py # VoiceScreeningAgent
158
+ │ │ │ │ ├── 📁 tools/
159
+ │ │ │ │ │ ├── twilio_client.py
160
+ │ │ │ │ │ ├── whisper_transcribe.py
161
+ │ │ │ │ │ └── tts_service.py
162
+ │ │ │ │ └── 📁 schemas/
163
+ │ │ │ │ ├── call_result.py
164
+ │ │ │ │ └── transcript.py
165
+ │ │ │
166
+ │ │ ├── 📁 scheduler/
167
+ │ │ │ │ ├── agent.py # SchedulerAgent
168
+ │ │ │ │ ├── 📁 tools/
169
+ │ │ │ │ │ ├── calendar_tool.py
170
+ │ │ │ │ │ ├── gmail_tool.py
171
+ │ │ │ │ │ └── slot_optimizer.py
172
+ │ │ │ │ └── 📁 schemas/
173
+ │ │ │ │ └── meeting_schema.py
174
+ │ │ │
175
+ │ │ └── 📁 decision/
176
+ │ │ ├── agent.py # DecisionAgent (final summarizer/Reporter)
177
+ │ │ └── 📁 schemas/
178
+ │ │ └── decision_report.py
179
+ │ │
180
+ │ ├── 📁 mcp_server/
181
+ │ │ ├── main.py
182
+ │ │ ├── 📁 endpoints/
183
+ │ │ ├── auth.py
184
+ │ │ └── schemas.py
185
+ │ │
186
+ │ ├── 📁 gradio/
187
+ │ │ ├── app.py # Main Gradio app (Hugging Face Space entry)
188
+ │ │ ├── dashboard.py # Live agent graph & logs view
189
+ │ │ ├── candidate_portal.py # Candidate upload / screening status
190
+ │ │ ├── hr_portal.py # HR review + interview approval
191
+ │ │ ├── components.py # Shared Gradio components
192
+ │ │ └── 📁 assets/ # Logos, CSS, etc.
193
+ │ │
194
+ │ ├── 📁 cv_ui/
195
+ │ │ ├── app.py
196
+ │ │
197
+ ��� ├── 📁 voice_screening_ui/
198
+ │ │ ├── app.py
199
+ │ │
200
+ │ │
201
+ │ ├── 📁 prompts/
202
+ │ │ ├── prompt_manager.py # Centralized prompt versioning
203
+ │ │ ├── cv_prompts.py
204
+ │ │ ├── voice_prompts.py
205
+ │ │ └── scheduler_prompts.py
206
+ │ │
207
+ │ ├── 📁 database/
208
+ │ │ ├── models.py # SQLAlchemy models
209
+ │ │ ├── db_client.py # Connection & CRUD
210
+ │ │ └── context_sync.py # Cognitive offloading (context ⇄ DB)
211
+ │ │
212
+ │ ├── main.py # CLI runner / local orchestrator entry
213
+ │ └── config.py # Environment configuration
214
+
215
+ ├── 📁 tests/
216
+ │ │ ├── test_cv_agent.py
217
+ │ │ ├── test_voice_agent.py
218
+ │ │ ├── test_scheduler_agent.py
219
+ │ │ ├── test_mcp_server.py
220
+ │ │ └── test_integration.py
221
+
222
+ ├── .env.example
223
+ ├── requirements.txt
224
+ ├── Dockerfile
225
+ ├── app.py # Shortcut to src/ui/app.py
226
+ ├── README.md
227
+ └── LICENSE
228
+ ```
229
+
230
+ ## ***`Multi Agent System Architecture`***
231
+ Below you will find an overview of the subagent components that mnake upo the entire system. More detailed information and brainstorming is decicated to the `docs/agents/..` directory.
232
+
233
+ ### 1) ***`Orchestrator`***
234
+ #### Overview
235
+
236
+ The orchestrator agent is reponsible for **supervising** and **triggering** the ***tasks of the subagents***.
237
+
238
+ > For more planning and info, go to `docs/agents/agent_orchestrator.md`
239
+
240
+ ### 2) ***`CV Screener`***
241
+ #### Overview
242
+ The cv screening agent deals with scanning the applicant's CV's, and deciding who are fruitful versus unpromising candidates as a first filtering step.
243
+
244
+ > For more planning and info, go to `docs/agents/cv_screening.md`
245
+
246
+ ### 3) 🎙️ ***`Voice Screening Agent`***
247
+
248
+ #### Overview
249
+ The **Voice Screening Agent** conducts automated phone interviews and integrates with the **LangGraph HR Orchestrator**.
250
+ It uses **Twilio** for phone calls, **Whisper/ASR** for speech-to-text, **ElevenLabs** for natural voice output, and **LangGraph** for dialogue logic.
251
+
252
+ > For more planning and info, go to `docs/agents/voice_screening.md`
253
+
254
+ ### 4) ***`Google MCP Agents`***
255
+ #### Overview
256
+ The google mcp agents will be resposnible to:
257
+ a) writing emails
258
+ b) scheduling and menaging google calendar events
259
+
260
+ It adviseable to break this up into two subagents, to get rid of `context poisoning`.
261
+
262
+ > For more planning and info, go to `docs/agents/google_mcp_agent.md`
263
+
264
+ ### 4) ***`LLM as a Judge`***
265
+ #### Overview
266
+ LLM-as-a-judge will be leveraged to judge call screening results.
267
+
268
+ > For more planning and info, go to `docs/agents/judging_agent.md`
269
+
270
+ ## 🗄️ ***`Data Layer`***
271
+
272
+ The system uses a unified **SQLAlchemy-based database** for both **candidate data management** and **context engineering**.
273
+
274
+ ### 📦 Purpose
275
+ | Data Type | Description |
276
+ |------------|--------------|
277
+ | 🧾 **Candidates** | Stores CVs, parsed data, and screening results |
278
+ | 🎙️ **Voice Results** | Saves transcripts, evaluations, and tone analysis |
279
+ | 🗓️ **Scheduling** | Tracks HR availability and confirmed interviews |
280
+ | 🧠 **Agent Context Memory** | Enables **cognitive offloading** — storing reasoning traces and summaries so the active context stays uncluttered and information can be recalled when needed |
281
+ | 📚 **Logs / Tool History** | Archives tool interactions and results for transparency and reuse |
282
+
283
+ We use [**SQLAlchemy**](https://www.sqlalchemy.org) as the ORM layer to manage both structured candidate data and **persistent agent memory**, allowing the system to offload, summarize, and retrieve context efficiently across sessions.
284
+
285
+ ## 🗃️ ***`Prompt Archive`***
286
+
287
+ To ensure consistent behavior and easy experimentation across subagents, the system includes a **centralized prompt management layer**.
288
+
289
+ ### 📦 Purpose
290
+ | Component | Description |
291
+ |------------|--------------|
292
+ | 🧠 **Prompt Templates** | Stores standardized prompts for each subagent (CV screening, voice screening, scheduling) |
293
+ | 🔄 **Prompt Versioning** | Allows tracking and updating of prompt iterations without changing agent code |
294
+ | 🧩 **Dynamic Injection** | Enables context-dependent prompt construction using retrieved memory or database summaries |
295
+ | 📚 **Archive** | Keeps older prompt variants for reproducibility and ablation testing |
296
+
297
+ ## 📺 ***`Gradio Interface`***
298
+
299
+ We use **Gradio** to demonstrate our agent's reasoning, planning, and tool use interactively — fully aligned with the **Agents & MCP Hackathon** focus on **context engineering** and **user value**.
300
+
301
+ ### 🧩 Key Features
302
+ | Section | Purpose |
303
+ |----------|----------|
304
+ | 🧍 **Candidate Portal** | Upload CVs, submit applications, and view screening results |
305
+ | 🧑‍💼 **HR Portal** | Review shortlisted candidates, trigger voice screenings, and schedule interviews |
306
+ | 🧠 **Agent Dashboard** | Visualizes the current plan, tool calls, and reasoning traces in real time |
307
+ | ⚙️ **Tool Integration** | Shows live MCP actions (Gmail send, Calendar scheduling) with status updates |
308
+ | 📊 **Context View** | Displays agent memory, current workflow stage, and adaptive plan updates |
309
+
310
+ #### Context Engineering Visualization?
311
+ This is what judges really care about — it must show that the system is agentic (reasoning, memory, planning).
312
+ 🧠 Agent Plan Viewer
313
+ gr.JSON() or custom visual showing the current plan state, e.g.:
314
+ ```json
315
+ {
316
+ "plan": [
317
+ "1. Screen CVs ✅",
318
+ "2. Invite for voice screening 🔄",
319
+ "3. Schedule HR interview ⬜",
320
+ "4. Await HR decision ⬜"
321
+ ]
322
+ }
323
+ ```
324
+ 🗺️ Live Plan Progress
325
+ - Use a progress bar or color-coded status list of steps.
326
+ - Judges must see autonomous transitions (from one step to another).
327
+
328
+ 💬 Reasoning Log / Memory
329
+ - Stream or text box showing LLM thought traces or context summary:
330
+ - “Detected strong match for Data Scientist role.”
331
+ - “Candidate completed voice interview; confidence: 8.4/10.”
332
+ - “Next step: scheduling HR interview.”
333
+
334
+ ⚙️ Tool Call Trace
335
+ - Small table showing:
336
+
337
+ | Time | Tool | Action | Result |
338
+ | ----- | -------- | ---------------- | --------- |
339
+ | 12:05 | Gmail | `send_invite()` | Sent |
340
+ | 12:06 | Calendar | `create_event()` | Confirmed |
341
+
342
+ ## 🔗 ***`MCP Integration (Best Practice Setup)`***
343
+
344
+ To align fully with the **Agents & MCP Hackathon** standards, our system will use or extend a **standardized MCP server** for integrations such as **Gmail** and **Google Calendar** — and potentially **Scion Voice** in later stages.
345
+
346
+ **`Inspired by`** [Huggingface MCP Course](https://huggingface.co/learn/mcp-course/en/unit2/introduction): shows how to build an MCP app.
347
+
348
+ ### 🧩 Why MCP?
349
+ | Benefit | Description |
350
+ |----------|--------------|
351
+ | ✅ **Standardized** | Exposes Gmail & Calendar as reusable MCP tools with a consistent schema |
352
+ | 🔐 **Secure** | OAuth handled once server-side — no tokens or secrets stored in the agent |
353
+ | 🧱 **Modular** | Clean separation between the agent's reasoning logic and the integration layer |
354
+ | 🔄 **Reusable** | Same MCP server can serve multiple projects or agents |
355
+ | 🚀 **Hackathon-Ready** | Directly fulfills the “use MCP tools or external APIs” requirement |
356
+
357
+ ---
358
+
359
+ ### ⚙️ Why Use MCP Instead of Just Defining Tools
360
+ | Approach | Limitation / Risk | MCP Advantage |
361
+ |-----------|-------------------|----------------|
362
+ | **Custom-defined tools** (e.g., direct Gmail API calls in code) | Each project must re-implement auth, rate limits, and API logic | MCP provides a *shared, pre-authorized* interface any agent can use |
363
+ | **Embedded credentials** in `.env` | Security risk, harder for judges to test | Credentials handled server-side — no secrets in the repo |
364
+ | **Tight coupling** between agent and tool | Hard to swap or extend integrations | MCP creates a plug-and-play API boundary between reasoning and execution |
365
+ | **Limited reuse** | Tools only exist in one codebase | MCP servers can expose many tools to multiple agents dynamically |
366
+
367
+ MCP turns these one-off integrations into **standardized, composable building blocks** that work across agents, organizations, or platforms — the same philosophy used by **Anthropic**, **LangChain**, and **Hugging Face** in 2025 agent ecosystems.
368
+
369
+
370
+ We will build or extend the open-source [**mcp-gsuite**](https://github.com/MarkusPfundstein/mcp-gsuite) server and host it securely on **Google Cloud Run**.
371
+ This server manages authentication, token refresh, and rate limiting — while exposing standardized MCP actions like:
372
+ ```json
373
+ {
374
+ "action": "gmail.send",
375
+ "parameters": { "to": "candidate@example.com", "subject": "Interview Invite", "body": "..." }
376
+ }
377
+ ```
378
+
379
+ and
380
+
381
+ ```json
382
+ {
383
+ "action": "calendar.create_event",
384
+ "parameters": { "summary": "HR Interview", "start": "...", "end": "..." }
385
+ }
386
+ ```
387
+ This architecture lets our HR agent (and future projects) perform real email and scheduling actions via secure MCP endpoints — giving judges a safe, live demo of true agentic behavior with no local credential setup required.
388
+
389
+ ## 🧠 ***`Agent Supervisor — Why Parlant + LangGraph`***
390
+
391
+ LangGraph provides a powerful orchestration backbone for planning, reasoning, and executing multi-agent workflows.
392
+ However, its common **supervisor pattern** has a key limitation: the supervisor routes each user query to **only one sub-agent** at a time.
393
+
394
+ ### ⚠️ Example Problem
395
+ > “I uploaded my CV yesterday. Can I also reschedule my interview — and how long is the voice call?”
396
+
397
+ A standard LangGraph supervisor would forward this entire message to, say, the **CV Screening Agent**,
398
+ missing the **scheduling** and **voice screening** parts — causing incomplete or fragmented responses.
399
+
400
+ ### 💡 Parlant as the Fix
401
+ **[Parlant](https://github.com/emcie-co/parlant)** solves this by replacing single-route logic with **dynamic guideline activation**.
402
+ Instead of rigid routing, it loads multiple relevant *guidelines* into context simultaneously, allowing coherent handling of mixed intents.
403
+
404
+ ```python
405
+ agent.create_guideline(
406
+ condition="User asks about rescheduling",
407
+ action="Call SchedulerAgent via LangGraph tool"
408
+ )
409
+
410
+ agent.create_guideline(
411
+ condition="User asks about voice screening duration",
412
+ action="Query VoiceScreeningAgent"
413
+ )
414
+ ```
415
+
416
+ If a user blends both topics, ***both guidelines trigger***, producing a unified, context-aware response.
417
+
418
+ ### ⚙️ Why Combine Them
419
+ | Layer | Framework | Role |
420
+ | ----------------------------- | ------------- | ----------------------------------------------------------------------- |
421
+ | 🧠 **Workflow Orchestration** | **LangGraph** | Executes structured agent workflows (CV → Voice → Schedule → Decision). |
422
+ | 💬 **Conversational Layer** | **Parlant** | Dynamically manages mixed intents using guideline-based reasoning. |
423
+ | 🔧 **Integration Layer** | **MCP Tools** | Provides standardized access to Gmail, Calendar, and Voice APIs. |
424
+
425
+
426
+ Together, ***Parlant + LangGraph*** merge structured planning with conversational adaptability —
427
+ enabling our HR agent to reason, plan, and respond naturally to complex, multi-topic interactions.
428
+
429
+ ## ✨ ***`Agentic Enhancements [BONUS]`***
430
+
431
+ To make the system more **autonomous, interpretable, and resilient**, we integrated a few lightweight yet powerful improvements:
432
+
433
+ - 🧠 **Self-Reflection** – before executing a step, the agent briefly states *why* it's taking that action, improving reasoning transparency.
434
+ - 🔄 **Adaptive Re-Planning** – if a subagent or tool call fails (e.g., no calendar slot, missing response, or API timeout), the main planner automatically updates its plan — skipping, retrying, or re-ordering steps instead of stopping.
435
+ - 🧮 **LLM Self-Evaluation** – after each stage (CV, voice, scheduling), a lightweight judge model rates the result and adds feedback for the next step.
436
+ - 🗂️ **Context Summary** – the dashboard displays a live summary of all candidates, their current stage, and key outcomes.
437
+ - 🤝 **Human-in-the-Loop Checkpoint** – HR receives a short confirmation prompt before final scheduling to ensure responsible autonomy.
438
+
439
+ These enhancements demonstrate **true agentic behavior** — autonomous planning, adaptive execution, and transparent reasoning — in a simple, explainable way.
440
+
441
+ ## 👥 ***`Team`***
442
+ | Member |
443
+ | -------- |
444
+ | [Sebastian Wefers](https://github.com/Ocean-code-1995) |
445
+ | [Owen Kaplinsky](https://github.com/owenkaplinsky) |
446
+ | [SrikarMK](https://github.com/Srikarmk) |
447
+ | [Dmitri Moscoglo](https://github.com/DimiM99) |
448
+
449
+ # ***`License`***
450
+
451
+ This project includes and builds upon [gmail-mcp](https://github.com/theposch/gmail-mcp),
452
+ which is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
453
+
454
+ This repository extends gmail-mcp for experimental integration and automation with Claude Desktop.
455
+ All modifications are distributed under the same GPLv3 license.
456
+
457
+ > **Note:** The original gmail-mcp code has not been modified at this stage.
langgraph.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "dependencies": ["./src"],
3
+ "graphs": {
4
+ "supervisor": "src.agents.supervisor.supervisor_v2:supervisor_agent"
5
+ }
6
+ }
7
+
package-lock.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "recruitment-agent3",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }
requirements/agent.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ langchain
2
+ langchain-openai
3
+ langgraph
requirements/all.txt ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Consolidated requirements with all dependencies
2
+ # Deduplicated from all individual requirement files
3
+
4
+ # Base dependencies
5
+ python-dotenv
6
+ pydantic>=2.0
7
+ pydantic-settings
8
+ promptlayer
9
+
10
+ # LangChain & LangGraph
11
+ langchain
12
+ langchain-openai
13
+ langchain-community
14
+ langchain-mcp-adapters
15
+ langgraph
16
+ langgraph-cli
17
+
18
+ # API Framework
19
+ fastapi
20
+ uvicorn[standard]
21
+
22
+ # Web & HTTP
23
+ websockets>=12.0
24
+ requests
25
+ aiohttp
26
+ httpx>=0.28.1
27
+
28
+ # Database
29
+ sqlalchemy
30
+ psycopg2-binary
31
+
32
+ # Google APIs
33
+ google-auth
34
+ google-auth-oauthlib
35
+ google-auth-httplib2
36
+ google-api-python-client
37
+
38
+ # MCP Server
39
+ mcp
40
+
41
+ # OpenAI
42
+ openai
43
+
44
+ # UI & Visualization
45
+ streamlit
46
+ rich
47
+
48
+ # PDF & Image Processing
49
+ pypdfium2
50
+ pillow
51
+ ftfy
52
+
53
+ # Search & Tools
54
+ duckduckgo-search
55
+ langchain-tavily
56
+
57
+ # Email validation
58
+ email-validator
59
+ pydantic[email]
60
+
61
+ # Date utilities
62
+ python-dateutil
63
+
64
+ gradio==6.0.1
requirements/api.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # API Layer dependencies
2
+ -r base.txt
3
+
4
+ fastapi
5
+ uvicorn[standard]
6
+ pydantic>=2.0
7
+
requirements/base.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ python-dotenv
2
+ pydantic
3
+ pydantic-settings
4
+ promptlayer
requirements/cv_ui.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CV Upload UI requirements
2
+ # Includes base requirements
3
+ -r base.txt
4
+ -r db.txt
5
+
6
+ openai
7
+
8
+ # Streamlit for UI
9
+ streamlit
10
+
11
+ # PDF processing
12
+ pypdfium2
13
+ pillow
14
+ ftfy
15
+
requirements/db.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # data base requirements
2
+ -r base.txt
3
+ sqlalchemy
4
+ psycopg2-binary
requirements/mcp_calendar.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Google Calendar MCP Server requirements
2
+ # Includes base requirements
3
+ -r base.txt
4
+
5
+ # MCP server framework
6
+ mcp
7
+
8
+ # Google Calendar API
9
+ google-auth
10
+ google-auth-oauthlib
11
+ google-api-python-client
12
+
13
+ # Date utilities
14
+ python-dateutil
15
+
requirements/mcp_gmail.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Gmail MCP Server requirements
2
+ # Includes base requirements
3
+ -r base.txt
4
+
5
+ # MCP server framework
6
+ mcp
7
+
8
+ # Gmail API
9
+ google-auth
10
+ google-auth-oauthlib
11
+ google-api-python-client
12
+ google-auth-httplib2
13
+
14
+ # HTTP client
15
+ httpx>=0.28.1
16
+
requirements/requirements.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ google-auth
2
+ langgraph
3
+ langchain
4
+ langchain-openai
5
+ langchain-mcp-adapters
6
+ duckduckgo-search
7
+ langchain-tavily
8
+ langchain-community
9
+ langgraph-cli
10
+ promptlayer
11
+
12
+ mcp
13
+ pypdfium2
14
+ pillow
15
+ ftfy
16
+ sqlalchemy
17
+ psycopg2-binary
18
+ pydantic
19
+ pydantic-settings
20
+ python-dotenv
21
+ openai
22
+ pypdfium2
23
+ Pillow
24
+ ftfy
requirements/supervisor.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Supervisor Agent requirements
2
+ # Includes base requirements
3
+ -r base.txt
4
+
5
+ # LangGraph for agent orchestration
6
+ langgraph
7
+ langchain-community
8
+ langchain-mcp-adapters
9
+ streamlit
10
+ rich
11
+ requests
12
+
requirements/voice_proxy.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ -r base.txt
2
+ -r db.txt
3
+ fastapi
4
+ uvicorn[standard]
5
+ websockets>=12.0
6
+ requests
7
+ asyncio
8
+ aiohttp
9
+ email-validator
10
+ pydantic[email]
requirements/voice_screening_ui.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ -r base.txt
2
+ streamlit
3
+ uvicorn[standard]
4
+ requests
5
+
6
+
scripts/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ """CLI scripts package."""
2
+
scripts/db/__init__.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ """Database CLI utilities."""
2
+
3
+ import sys
4
+ import os
5
+
6
+ # Add project root to sys.path for all db scripts
7
+ project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../'))
8
+ if project_root not in sys.path:
9
+ sys.path.insert(0, project_root)
10
+
scripts/db/debug_all.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Run all database debug checks.
3
+
4
+ Run as follows:
5
+ >>> POSTGRES_HOST=localhost POSTGRES_PORT=5433 POSTGRES_PASSWORD=password123 python -m scripts.db.debug_all
6
+
7
+ This runs:
8
+ 1. Connection test
9
+ 2. Session query test
10
+ 3. List existing candidates
11
+ """
12
+
13
+ import sys
14
+ import os
15
+
16
+ # Add project root to sys.path
17
+ project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../'))
18
+ if project_root not in sys.path:
19
+ sys.path.insert(0, project_root)
20
+
21
+ from scripts.db.test_connection import test_connection
22
+ from scripts.db.test_session import test_session_query
23
+ from scripts.db.list_candidates import list_candidates
24
+
25
+
26
+ def run_all_checks() -> None:
27
+ """Run all database diagnostic checks."""
28
+ print("=" * 50)
29
+ print("🔍 DATABASE DIAGNOSTICS")
30
+ print("=" * 50)
31
+
32
+ # 1. Test connection
33
+ conn_ok = test_connection()
34
+
35
+ if not conn_ok:
36
+ print("\n⛔ Stopping - connection failed")
37
+ return
38
+
39
+ print()
40
+
41
+ # 2. Test session
42
+ session_ok = test_session_query()
43
+
44
+ if not session_ok:
45
+ print("\n⛔ Stopping - session failed")
46
+ return
47
+
48
+ print()
49
+
50
+ # 3. List candidates
51
+ list_candidates()
52
+
53
+ print()
54
+ print("=" * 50)
55
+ print("✅ All checks completed")
56
+ print("=" * 50)
57
+
58
+
59
+ if __name__ == "__main__":
60
+ run_all_checks()
scripts/db/list_candidates.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ List candidates in the database.
3
+
4
+ Run standalone:
5
+ >>> POSTGRES_HOST=localhost POSTGRES_PORT=5433 python scripts/db/list_candidates.py
6
+ """
7
+
8
+ from sqlalchemy.exc import ProgrammingError
9
+
10
+ # Ensure project root is in path
11
+ import scripts.db # noqa: F401
12
+
13
+ from src.database.candidates.client import SessionLocal
14
+ from src.database.candidates.models import Candidate
15
+
16
+
17
+ def list_candidates(limit: int = 10) -> bool:
18
+ """
19
+ Check and list existing candidates in the database.
20
+
21
+ Args:
22
+ limit: Maximum number of candidates to display.
23
+
24
+ Returns:
25
+ True if query successful, False otherwise.
26
+ """
27
+ print("--- 🧾 Checking Existing Candidates ---")
28
+ session = SessionLocal()
29
+ try:
30
+ count = session.query(Candidate).count()
31
+ print(f"📊 Found {count} candidate(s) in the database.")
32
+
33
+ if count == 0:
34
+ print("⚠️ No candidates found.")
35
+ else:
36
+ print(f"\n👀 Listing candidates (up to {limit}):")
37
+ candidates = (
38
+ session.query(Candidate)
39
+ .order_by(Candidate.full_name)
40
+ .limit(limit)
41
+ .all()
42
+ )
43
+ for c in candidates:
44
+ print(f" - {c.full_name} | {c.email} | Status: {c.status}")
45
+
46
+ return True
47
+
48
+ except ProgrammingError as e:
49
+ print("❌ Table 'candidates' does not exist or schema not initialized.")
50
+ print("ℹ️ Try running your DB initialization script or migrations.")
51
+ print(f"Error: {e}")
52
+ return False
53
+ except Exception as e:
54
+ print("❌ Error during candidate check.")
55
+ print(f"Error: {e}")
56
+ return False
57
+ finally:
58
+ session.close()
59
+
60
+
61
+ if __name__ == "__main__":
62
+ list_candidates()
63
+
scripts/db/test_connection.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test basic database connection.
3
+
4
+ Run standalone:
5
+ >>> POSTGRES_HOST=localhost POSTGRES_PORT=5433 python scripts/db/test_connection.py
6
+ """
7
+
8
+ import os
9
+ from sqlalchemy import text
10
+
11
+ # Ensure project root is in path
12
+ import scripts.db # noqa: F401
13
+
14
+ from src.database.candidates.client import get_engine
15
+
16
+
17
+ def test_connection() -> bool:
18
+ """
19
+ Test basic database connectivity.
20
+
21
+ Returns:
22
+ True if connection successful, False otherwise.
23
+ """
24
+ print("--- Testing Database Connection ---")
25
+
26
+ # Print environment info
27
+ print(f"POSTGRES_HOST (env): {os.environ.get('POSTGRES_HOST')}")
28
+ print(f"POSTGRES_PORT (env): {os.environ.get('POSTGRES_PORT')}")
29
+
30
+ try:
31
+ engine = get_engine()
32
+ print(f"Engine URL: {engine.url}")
33
+
34
+ with engine.connect() as connection:
35
+ print("✅ Connection successful!")
36
+ result = connection.execute(text("SELECT 1"))
37
+ print(f"✅ SELECT 1 result: {result.fetchone()}")
38
+ return True
39
+
40
+ except Exception as e:
41
+ print("\n❌ Connection FAILED")
42
+ print(f"Error type: {type(e).__name__}")
43
+ print(f"Error message: {str(e)}")
44
+ import traceback
45
+ traceback.print_exc()
46
+ return False
47
+
48
+
49
+ if __name__ == "__main__":
50
+ test_connection()
51
+
scripts/db/test_session.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test database session and query execution.
3
+
4
+ Run standalone:
5
+ >>> POSTGRES_HOST=localhost POSTGRES_PORT=5433 python scripts/db/test_session.py
6
+ """
7
+
8
+ from sqlalchemy import text
9
+
10
+ # Ensure project root is in path
11
+ import scripts.db # noqa: F401
12
+
13
+ from src.database.candidates.client import SessionLocal
14
+
15
+
16
+ def test_session_query() -> bool:
17
+ """
18
+ Test session creation and basic query execution.
19
+
20
+ Returns:
21
+ True if session works, False otherwise.
22
+ """
23
+ print("--- Testing Session Query ---")
24
+ session = SessionLocal()
25
+ try:
26
+ result = session.execute(text("SELECT now()"))
27
+ print(f"✅ Session execute successful: {result.fetchone()[0]}")
28
+ return True
29
+
30
+ except Exception as e:
31
+ print("\n❌ Session Query FAILED")
32
+ print(f"Error: {e}")
33
+ return False
34
+ finally:
35
+ session.close()
36
+
37
+
38
+ if __name__ == "__main__":
39
+ test_session_query()
40
+